summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/accessibility/Kconfig33
-rw-r--r--drivers/accessibility/Makefile1
-rw-r--r--drivers/accessibility/braille/Makefile1
-rw-r--r--drivers/accessibility/braille/braille_console.c397
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/ac.c12
-rw-r--r--drivers/acpi/battery.c12
-rw-r--r--drivers/acpi/bay.c2
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/button.c24
-rw-r--r--drivers/acpi/dispatcher/dsfield.c173
-rw-r--r--drivers/acpi/dispatcher/dsinit.c2
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c57
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c2
-rw-r--r--drivers/acpi/dispatcher/dsobject.c101
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c260
-rw-r--r--drivers/acpi/dispatcher/dsutils.c167
-rw-r--r--drivers/acpi/dispatcher/dswexec.c78
-rw-r--r--drivers/acpi/dispatcher/dswload.c37
-rw-r--r--drivers/acpi/dispatcher/dswscope.c2
-rw-r--r--drivers/acpi/dispatcher/dswstate.c517
-rw-r--r--drivers/acpi/ec.c251
-rw-r--r--drivers/acpi/event.c8
-rw-r--r--drivers/acpi/events/evevent.c2
-rw-r--r--drivers/acpi/events/evgpe.c6
-rw-r--r--drivers/acpi/events/evgpeblk.c2
-rw-r--r--drivers/acpi/events/evmisc.c92
-rw-r--r--drivers/acpi/events/evregion.c4
-rw-r--r--drivers/acpi/events/evrgnini.c2
-rw-r--r--drivers/acpi/events/evsci.c2
-rw-r--r--drivers/acpi/events/evxface.c23
-rw-r--r--drivers/acpi/events/evxfevnt.c2
-rw-r--r--drivers/acpi/events/evxfregn.c2
-rw-r--r--drivers/acpi/executer/exconfig.c105
-rw-r--r--drivers/acpi/executer/exconvrt.c2
-rw-r--r--drivers/acpi/executer/excreate.c117
-rw-r--r--drivers/acpi/executer/exdump.c69
-rw-r--r--drivers/acpi/executer/exfield.c63
-rw-r--r--drivers/acpi/executer/exfldio.c46
-rw-r--r--drivers/acpi/executer/exmisc.c2
-rw-r--r--drivers/acpi/executer/exmutex.c237
-rw-r--r--drivers/acpi/executer/exnames.c2
-rw-r--r--drivers/acpi/executer/exoparg1.c25
-rw-r--r--drivers/acpi/executer/exoparg2.c21
-rw-r--r--drivers/acpi/executer/exoparg3.c3
-rw-r--r--drivers/acpi/executer/exoparg6.c10
-rw-r--r--drivers/acpi/executer/exprep.c17
-rw-r--r--drivers/acpi/executer/exregion.c10
-rw-r--r--drivers/acpi/executer/exresnte.c12
-rw-r--r--drivers/acpi/executer/exresolv.c55
-rw-r--r--drivers/acpi/executer/exresop.c13
-rw-r--r--drivers/acpi/executer/exstore.c119
-rw-r--r--drivers/acpi/executer/exstoren.c2
-rw-r--r--drivers/acpi/executer/exstorob.c2
-rw-r--r--drivers/acpi/executer/exsystem.c3
-rw-r--r--drivers/acpi/executer/exutils.c67
-rw-r--r--drivers/acpi/fan.c49
-rw-r--r--drivers/acpi/glue.c20
-rw-r--r--drivers/acpi/hardware/hwacpi.c2
-rw-r--r--drivers/acpi/hardware/hwgpe.c2
-rw-r--r--drivers/acpi/hardware/hwregs.c2
-rw-r--r--drivers/acpi/hardware/hwsleep.c16
-rw-r--r--drivers/acpi/hardware/hwtimer.c2
-rw-r--r--drivers/acpi/namespace/nsaccess.c101
-rw-r--r--drivers/acpi/namespace/nsalloc.c2
-rw-r--r--drivers/acpi/namespace/nsdump.c11
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c2
-rw-r--r--drivers/acpi/namespace/nseval.c2
-rw-r--r--drivers/acpi/namespace/nsinit.c12
-rw-r--r--drivers/acpi/namespace/nsload.c6
-rw-r--r--drivers/acpi/namespace/nsnames.c8
-rw-r--r--drivers/acpi/namespace/nsobject.c2
-rw-r--r--drivers/acpi/namespace/nsparse.c33
-rw-r--r--drivers/acpi/namespace/nssearch.c2
-rw-r--r--drivers/acpi/namespace/nsutils.c2
-rw-r--r--drivers/acpi/namespace/nswalk.c6
-rw-r--r--drivers/acpi/namespace/nsxfeval.c15
-rw-r--r--drivers/acpi/namespace/nsxfname.c2
-rw-r--r--drivers/acpi/namespace/nsxfobj.c2
-rw-r--r--drivers/acpi/osl.c1
-rw-r--r--drivers/acpi/parser/psargs.c63
-rw-r--r--drivers/acpi/parser/psloop.c61
-rw-r--r--drivers/acpi/parser/psopcode.c38
-rw-r--r--drivers/acpi/parser/psparse.c45
-rw-r--r--drivers/acpi/parser/psscope.c2
-rw-r--r--drivers/acpi/parser/pstree.c4
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/parser/pswalk.c2
-rw-r--r--drivers/acpi/parser/psxface.c2
-rw-r--r--drivers/acpi/power.c13
-rw-r--r--drivers/acpi/processor_core.c79
-rw-r--r--drivers/acpi/processor_idle.c31
-rw-r--r--drivers/acpi/processor_perflib.c13
-rw-r--r--drivers/acpi/processor_thermal.c1
-rw-r--r--drivers/acpi/processor_throttling.c1
-rw-r--r--drivers/acpi/resources/rsaddr.c2
-rw-r--r--drivers/acpi/resources/rscalc.c26
-rw-r--r--drivers/acpi/resources/rscreate.c2
-rw-r--r--drivers/acpi/resources/rsdump.c10
-rw-r--r--drivers/acpi/resources/rsinfo.c2
-rw-r--r--drivers/acpi/resources/rsio.c41
-rw-r--r--drivers/acpi/resources/rsirq.c45
-rw-r--r--drivers/acpi/resources/rslist.c2
-rw-r--r--drivers/acpi/resources/rsmemory.c2
-rw-r--r--drivers/acpi/resources/rsmisc.c13
-rw-r--r--drivers/acpi/resources/rsutils.c8
-rw-r--r--drivers/acpi/resources/rsxface.c2
-rw-r--r--drivers/acpi/sbs.c35
-rw-r--r--drivers/acpi/scan.c63
-rw-r--r--drivers/acpi/sleep/main.c42
-rw-r--r--drivers/acpi/sleep/proc.c26
-rw-r--r--drivers/acpi/system.c27
-rw-r--r--drivers/acpi/tables/tbfadt.c2
-rw-r--r--drivers/acpi/tables/tbfind.c34
-rw-r--r--drivers/acpi/tables/tbinstal.c24
-rw-r--r--drivers/acpi/tables/tbutils.c4
-rw-r--r--drivers/acpi/tables/tbxface.c91
-rw-r--r--drivers/acpi/tables/tbxfroot.c2
-rw-r--r--drivers/acpi/thermal.c87
-rw-r--r--drivers/acpi/utilities/utalloc.c4
-rw-r--r--drivers/acpi/utilities/utcache.c2
-rw-r--r--drivers/acpi/utilities/utcopy.c61
-rw-r--r--drivers/acpi/utilities/utdebug.c19
-rw-r--r--drivers/acpi/utilities/utdelete.c23
-rw-r--r--drivers/acpi/utilities/uteval.c2
-rw-r--r--drivers/acpi/utilities/utglobal.c49
-rw-r--r--drivers/acpi/utilities/utinit.c5
-rw-r--r--drivers/acpi/utilities/utmath.c4
-rw-r--r--drivers/acpi/utilities/utmisc.c6
-rw-r--r--drivers/acpi/utilities/utmutex.c2
-rw-r--r--drivers/acpi/utilities/utobject.c8
-rw-r--r--drivers/acpi/utilities/utresrc.c2
-rw-r--r--drivers/acpi/utilities/utstate.c2
-rw-r--r--drivers/acpi/utilities/utxface.c41
-rw-r--r--drivers/acpi/utils.c2
-rw-r--r--drivers/acpi/video.c307
-rw-r--r--drivers/ata/Kconfig21
-rw-r--r--drivers/ata/Makefile3
-rw-r--r--drivers/ata/ahci.c6
-rw-r--r--drivers/ata/ata_generic.c6
-rw-r--r--drivers/ata/ata_piix.c25
-rw-r--r--drivers/ata/libata-core.c4
-rw-r--r--drivers/ata/libata-eh.c2
-rw-r--r--drivers/ata/libata-scsi.c507
-rw-r--r--drivers/ata/libata-sff.c6
-rw-r--r--drivers/ata/libata.h28
-rw-r--r--drivers/ata/pata_acpi.c6
-rw-r--r--drivers/ata/pata_atiixp.c4
-rw-r--r--drivers/ata/pata_bf54x.c124
-rw-r--r--drivers/ata/pata_rb532_cf.c (renamed from drivers/ata/pata_rb500_cf.c)78
-rw-r--r--drivers/ata/pata_sch.c206
-rw-r--r--drivers/ata/pata_via.c11
-rw-r--r--drivers/ata/sata_inic162x.c646
-rw-r--r--drivers/ata/sata_mv.c765
-rw-r--r--drivers/atm/ambassador.c19
-rw-r--r--drivers/atm/ambassador.h2
-rw-r--r--drivers/base/base.h11
-rw-r--r--drivers/base/class.c639
-rw-r--r--drivers/base/core.c14
-rw-r--r--drivers/base/cpu.c10
-rw-r--r--drivers/base/driver.c10
-rw-r--r--drivers/base/firmware_class.c2
-rw-r--r--drivers/base/memory.c2
-rw-r--r--drivers/base/node.c2
-rw-r--r--drivers/base/power/main.c2
-rw-r--r--drivers/base/sys.c3
-rw-r--r--drivers/block/amiflop.c6
-rw-r--r--drivers/block/aoe/aoe.h1
-rw-r--r--drivers/block/aoe/aoecmd.c34
-rw-r--r--drivers/block/aoe/aoedev.c18
-rw-r--r--drivers/block/aoe/aoenet.c4
-rw-r--r--drivers/block/brd.c19
-rw-r--r--drivers/block/cciss.c12
-rw-r--r--drivers/block/cpqarray.c4
-rw-r--r--drivers/block/floppy.c6
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/nbd.c172
-rw-r--r--drivers/block/paride/pd.c4
-rw-r--r--drivers/block/pktcdvd.c13
-rw-r--r--drivers/block/ps3disk.c4
-rw-r--r--drivers/block/ub.c65
-rw-r--r--drivers/block/virtio_blk.c44
-rw-r--r--drivers/block/xen-blkfront.c2
-rw-r--r--drivers/block/z2ram.c2
-rw-r--r--drivers/bluetooth/hci_ldisc.c13
-rw-r--r--drivers/bluetooth/hci_usb.h21
-rw-r--r--drivers/cdrom/cdrom.c1
-rw-r--r--drivers/cdrom/viocd.c10
-rw-r--r--drivers/char/Kconfig10
-rw-r--r--drivers/char/agp/agp.h2
-rw-r--r--drivers/char/amiserial.c30
-rw-r--r--drivers/char/apm-emulation.c23
-rw-r--r--drivers/char/applicom.c4
-rw-r--r--drivers/char/consolemap.c1
-rw-r--r--drivers/char/cyclades.c432
-rw-r--r--drivers/char/drm/drmP.h8
-rw-r--r--drivers/char/drm/drm_sysfs.c2
-rw-r--r--drivers/char/drm/i830_dma.c18
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/i830_irq.c8
-rw-r--r--drivers/char/drm/i915_dma.c4
-rw-r--r--drivers/char/drm/i915_drv.h2
-rw-r--r--drivers/char/drm/radeon_cp.c2
-rw-r--r--drivers/char/ds1286.c3
-rw-r--r--drivers/char/epca.c315
-rw-r--r--drivers/char/esp.c611
-rw-r--r--drivers/char/generic_serial.c18
-rw-r--r--drivers/char/hpet.c10
-rw-r--r--drivers/char/hvsi.c52
-rw-r--r--drivers/char/i8k.c12
-rw-r--r--drivers/char/ip2/i2ellis.c194
-rw-r--r--drivers/char/ip2/i2ellis.h58
-rw-r--r--drivers/char/ip2/i2hw.h6
-rw-r--r--drivers/char/ip2/i2lib.c141
-rw-r--r--drivers/char/ip2/i2os.h127
-rw-r--r--drivers/char/ip2/ip2main.c144
-rw-r--r--drivers/char/ipmi/Makefile4
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c153
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c153
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c1508
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c206
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c708
-rw-r--r--drivers/char/ipmi/ipmi_si_sm.h89
-rw-r--r--drivers/char/ipmi/ipmi_smic_sm.c149
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c244
-rw-r--r--drivers/char/isicom.c171
-rw-r--r--drivers/char/istallion.c22
-rw-r--r--drivers/char/keyboard.c4
-rw-r--r--drivers/char/mem.c10
-rw-r--r--drivers/char/misc.c27
-rw-r--r--drivers/char/mmtimer.c424
-rw-r--r--drivers/char/moxa.c2999
-rw-r--r--drivers/char/moxa.h304
-rw-r--r--drivers/char/mspec.c12
-rw-r--r--drivers/char/mxser.c346
-rw-r--r--drivers/char/mxser.h137
-rw-r--r--drivers/char/n_hdlc.c35
-rw-r--r--drivers/char/n_r3964.c33
-rw-r--r--drivers/char/n_tty.c173
-rw-r--r--drivers/char/nozomi.c17
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c2
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.c26
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.h2
-rw-r--r--drivers/char/pcmcia/ipwireless/network.c15
-rw-r--r--drivers/char/pcmcia/ipwireless/network.h3
-rw-r--r--drivers/char/pcmcia/synclink_cs.c23
-rw-r--r--drivers/char/pty.c32
-rw-r--r--drivers/char/random.c297
-rw-r--r--drivers/char/rio/cirrus.h210
-rw-r--r--drivers/char/rio/rio_linux.c10
-rw-r--r--drivers/char/rio/rio_linux.h6
-rw-r--r--drivers/char/rio/riocmd.c19
-rw-r--r--drivers/char/rio/rioctrl.c37
-rw-r--r--drivers/char/rio/riointr.c5
-rw-r--r--drivers/char/rio/rioparam.c70
-rw-r--r--drivers/char/rio/riotty.c25
-rw-r--r--drivers/char/riscom8.c706
-rw-r--r--drivers/char/rocket.c43
-rw-r--r--drivers/char/rocket_int.h2
-rw-r--r--drivers/char/rtc.c6
-rw-r--r--drivers/char/serial167.c27
-rw-r--r--drivers/char/snsc.c18
-rw-r--r--drivers/char/snsc_event.c18
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/specialix.c111
-rw-r--r--drivers/char/stallion.c17
-rw-r--r--drivers/char/sx.c44
-rw-r--r--drivers/char/synclink.c45
-rw-r--r--drivers/char/synclink_gt.c80
-rw-r--r--drivers/char/synclinkmp.c41
-rw-r--r--drivers/char/sysrq.c46
-rw-r--r--drivers/char/toshiba.c5
-rw-r--r--drivers/char/tpm/Kconfig5
-rw-r--r--drivers/char/tpm/tpm_nsc.c2
-rw-r--r--drivers/char/tty_audit.c64
-rw-r--r--drivers/char/tty_io.c381
-rw-r--r--drivers/char/tty_ioctl.c126
-rw-r--r--drivers/char/viocons.c12
-rw-r--r--drivers/char/viotape.c9
-rw-r--r--drivers/char/vme_scc.c4
-rw-r--r--drivers/char/vt.c34
-rw-r--r--drivers/char/vt_ioctl.c452
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c6
-rw-r--r--drivers/cpufreq/Kconfig9
-rw-r--r--drivers/cpufreq/cpufreq.c29
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c8
-rw-r--r--drivers/cpufreq/cpufreq_stats.c2
-rw-r--r--drivers/edac/Kconfig2
-rw-r--r--drivers/edac/amd76x_edac.c7
-rw-r--r--drivers/edac/e752x_edac.c220
-rw-r--r--drivers/edac/e7xxx_edac.c13
-rw-r--r--drivers/edac/edac_core.h2
-rw-r--r--drivers/edac/edac_device.c39
-rw-r--r--drivers/edac/edac_mc.c29
-rw-r--r--drivers/edac/edac_module.h1
-rw-r--r--drivers/edac/edac_pci.c14
-rw-r--r--drivers/edac/edac_pci_sysfs.c11
-rw-r--r--drivers/edac/i3000_edac.c13
-rw-r--r--drivers/edac/i5000_edac.c14
-rw-r--r--drivers/edac/i82443bxgx_edac.c7
-rw-r--r--drivers/edac/i82860_edac.c7
-rw-r--r--drivers/edac/i82875p_edac.c9
-rw-r--r--drivers/edac/i82975x_edac.c8
-rw-r--r--drivers/edac/pasemi_edac.c7
-rw-r--r--drivers/edac/r82600_edac.c7
-rw-r--r--drivers/firewire/fw-sbp2.c4
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/dcdbas.c16
-rw-r--r--drivers/firmware/dell_rbu.c12
-rw-r--r--drivers/gpio/gpiolib.c4
-rw-r--r--drivers/gpio/pca953x.c28
-rw-r--r--drivers/gpio/pcf857x.c36
-rw-r--r--drivers/hid/hid-core.c6
-rw-r--r--drivers/hwmon/ads7828.c2
-rw-r--r--drivers/hwmon/adt7473.c45
-rw-r--r--drivers/hwmon/asb100.c4
-rw-r--r--drivers/hwmon/f75375s.c29
-rw-r--r--drivers/hwmon/lm75.c5
-rw-r--r--drivers/hwmon/smsc47b397.c17
-rw-r--r--drivers/hwmon/w83793.c26
-rw-r--r--drivers/hwmon/w83l785ts.c4
-rw-r--r--drivers/i2c/busses/i2c-amd756-s4882.c5
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-au1550.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c16
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c28
-rw-r--r--drivers/i2c/busses/i2c-piix4.c57
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c6
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c14
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-stub.c2
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c3
-rw-r--r--drivers/i2c/chips/ds1682.c10
-rw-r--r--drivers/i2c/chips/max6875.c3
-rw-r--r--drivers/i2c/chips/menelaus.c10
-rw-r--r--drivers/i2c/chips/tps65010.c34
-rw-r--r--drivers/i2c/chips/tsl2550.c10
-rw-r--r--drivers/i2c/i2c-core.c65
-rw-r--r--drivers/ide/Kconfig54
-rw-r--r--drivers/ide/ide-cd.c4
-rw-r--r--drivers/ide/ide-cd_verbose.c2
-rw-r--r--drivers/ide/ide-io.c3
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-probe.c15
-rw-r--r--drivers/ide/ide-proc.c7
-rw-r--r--drivers/ide/ide-tape.c2
-rw-r--r--drivers/ide/ide-taskfile.c3
-rw-r--r--drivers/ide/ide.c4
-rw-r--r--drivers/ide/legacy/falconide.c2
-rw-r--r--drivers/ide/legacy/macide.c3
-rw-r--r--drivers/ide/mips/swarm.c16
-rw-r--r--drivers/ide/pci/alim15x3.c52
-rw-r--r--drivers/ide/pci/cs5520.c2
-rw-r--r--drivers/ide/pci/siimage.c9
-rw-r--r--drivers/ieee1394/nodemgr.c5
-rw-r--r--drivers/infiniband/core/umem.c17
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c125
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h13
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_resource.c36
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h21
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.h1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c173
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.h2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_mem.c75
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c72
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h11
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c73
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h7
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c11
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c35
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c7
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c36
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c31
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c158
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c91
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba7220.c26
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c95
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c80
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h18
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c237
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c291
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c332
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sdma.c44
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c57
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c66
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_sdma.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c178
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h64
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c8
-rw-r--r--drivers/infiniband/hw/mlx4/doorbell.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c3
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c2
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c20
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_user.h10
-rw-r--r--drivers/infiniband/hw/nes/Kconfig1
-rw-r--r--drivers/infiniband/hw/nes/nes.h4
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c8
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c375
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h19
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c180
-rw-r--r--drivers/infiniband/hw/nes/nes_utils.c10
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h9
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c90
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c40
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c3
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h7
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c9
-rw-r--r--drivers/input/input.c18
-rw-r--r--drivers/input/keyboard/hilkbd.c4
-rw-r--r--drivers/input/misc/Kconfig2
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c5
-rw-r--r--drivers/input/serio/hp_sdc.c1
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c5
-rw-r--r--drivers/input/serio/i8042-io.h2
-rw-r--r--drivers/input/serio/q40kbd.c2
-rw-r--r--drivers/input/serio/serport.c2
-rw-r--r--drivers/input/tablet/aiptek.c16
-rw-r--r--drivers/input/tablet/gtco.c14
-rw-r--r--drivers/input/tablet/kbtab.c4
-rw-r--r--drivers/isdn/capi/capi.c9
-rw-r--r--drivers/isdn/capi/kcapi_proc.c24
-rw-r--r--drivers/isdn/divert/divert_procfs.c5
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c15
-rw-r--r--drivers/isdn/hardware/eicon/divasproc.c8
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c10
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c8
-rw-r--r--drivers/isdn/i4l/isdn_tty.c30
-rw-r--r--drivers/leds/led-class.c2
-rw-r--r--drivers/lguest/lguest_device.c68
-rw-r--r--drivers/lguest/lguest_user.c4
-rw-r--r--drivers/macintosh/Kconfig8
-rw-r--r--drivers/macintosh/Makefile5
-rw-r--r--drivers/macintosh/adb.c32
-rw-r--r--drivers/macintosh/therm_pm72.c31
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c6
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c20
-rw-r--r--drivers/macintosh/windfarm_pm121.c1040
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c4
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c10
-rw-r--r--drivers/mca/mca-legacy.c18
-rw-r--r--drivers/mca/mca-proc.c2
-rw-r--r--drivers/md/dm-emc.c2
-rw-r--r--drivers/md/dm-mpath-hp-sw.c1
-rw-r--r--drivers/md/dm-mpath-rdac.c1
-rw-r--r--drivers/md/dm-table.c5
-rw-r--r--drivers/md/linear.c1
-rw-r--r--drivers/md/md.c121
-rw-r--r--drivers/md/multipath.c1
-rw-r--r--drivers/md/raid0.c1
-rw-r--r--drivers/md/raid1.c31
-rw-r--r--drivers/md/raid10.c33
-rw-r--r--drivers/md/raid5.c59
-rw-r--r--drivers/media/Kconfig171
-rw-r--r--drivers/media/Makefile10
-rw-r--r--drivers/media/common/Makefile1
-rw-r--r--drivers/media/common/tuners/Kconfig163
-rw-r--r--drivers/media/common/tuners/Makefile26
-rw-r--r--drivers/media/common/tuners/mt2060.c (renamed from drivers/media/dvb/frontends/mt2060.c)0
-rw-r--r--drivers/media/common/tuners/mt2060.h (renamed from drivers/media/dvb/frontends/mt2060.h)4
-rw-r--r--drivers/media/common/tuners/mt2060_priv.h (renamed from drivers/media/dvb/frontends/mt2060_priv.h)0
-rw-r--r--drivers/media/common/tuners/mt20xx.c (renamed from drivers/media/video/mt20xx.c)0
-rw-r--r--drivers/media/common/tuners/mt20xx.h (renamed from drivers/media/video/mt20xx.h)2
-rw-r--r--drivers/media/common/tuners/mt2131.c (renamed from drivers/media/dvb/frontends/mt2131.c)0
-rw-r--r--drivers/media/common/tuners/mt2131.h (renamed from drivers/media/dvb/frontends/mt2131.h)4
-rw-r--r--drivers/media/common/tuners/mt2131_priv.h (renamed from drivers/media/dvb/frontends/mt2131_priv.h)0
-rw-r--r--drivers/media/common/tuners/mt2266.c (renamed from drivers/media/dvb/frontends/mt2266.c)0
-rw-r--r--drivers/media/common/tuners/mt2266.h (renamed from drivers/media/dvb/frontends/mt2266.h)4
-rw-r--r--drivers/media/common/tuners/mxl5005s.c4110
-rw-r--r--drivers/media/common/tuners/mxl5005s.h131
-rw-r--r--drivers/media/common/tuners/qt1010.c (renamed from drivers/media/dvb/frontends/qt1010.c)0
-rw-r--r--drivers/media/common/tuners/qt1010.h (renamed from drivers/media/dvb/frontends/qt1010.h)4
-rw-r--r--drivers/media/common/tuners/qt1010_priv.h (renamed from drivers/media/dvb/frontends/qt1010_priv.h)0
-rw-r--r--drivers/media/common/tuners/tda18271-common.c (renamed from drivers/media/dvb/frontends/tda18271-common.c)24
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c (renamed from drivers/media/dvb/frontends/tda18271-fe.c)168
-rw-r--r--drivers/media/common/tuners/tda18271-maps.c (renamed from drivers/media/dvb/frontends/tda18271-tables.c)0
-rw-r--r--drivers/media/common/tuners/tda18271-priv.h (renamed from drivers/media/dvb/frontends/tda18271-priv.h)9
-rw-r--r--drivers/media/common/tuners/tda18271.h (renamed from drivers/media/dvb/frontends/tda18271.h)2
-rw-r--r--drivers/media/common/tuners/tda827x.c (renamed from drivers/media/dvb/frontends/tda827x.c)0
-rw-r--r--drivers/media/common/tuners/tda827x.h (renamed from drivers/media/dvb/frontends/tda827x.h)4
-rw-r--r--drivers/media/common/tuners/tda8290.c (renamed from drivers/media/video/tda8290.c)8
-rw-r--r--drivers/media/common/tuners/tda8290.h (renamed from drivers/media/video/tda8290.h)2
-rw-r--r--drivers/media/common/tuners/tda9887.c (renamed from drivers/media/video/tda9887.c)0
-rw-r--r--drivers/media/common/tuners/tda9887.h (renamed from drivers/media/video/tda9887.h)2
-rw-r--r--drivers/media/common/tuners/tea5761.c (renamed from drivers/media/video/tea5761.c)0
-rw-r--r--drivers/media/common/tuners/tea5761.h (renamed from drivers/media/video/tea5761.h)2
-rw-r--r--drivers/media/common/tuners/tea5767.c (renamed from drivers/media/video/tea5767.c)6
-rw-r--r--drivers/media/common/tuners/tea5767.h (renamed from drivers/media/video/tea5767.h)2
-rw-r--r--drivers/media/common/tuners/tuner-i2c.h (renamed from drivers/media/video/tuner-i2c.h)0
-rw-r--r--drivers/media/common/tuners/tuner-simple.c (renamed from drivers/media/video/tuner-simple.c)0
-rw-r--r--drivers/media/common/tuners/tuner-simple.h (renamed from drivers/media/video/tuner-simple.h)2
-rw-r--r--drivers/media/common/tuners/tuner-types.c (renamed from drivers/media/video/tuner-types.c)0
-rw-r--r--drivers/media/common/tuners/tuner-xc2028-types.h (renamed from drivers/media/video/tuner-xc2028-types.h)0
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c (renamed from drivers/media/video/tuner-xc2028.c)0
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.h (renamed from drivers/media/video/tuner-xc2028.h)2
-rw-r--r--drivers/media/common/tuners/xc5000.c (renamed from drivers/media/dvb/frontends/xc5000.c)9
-rw-r--r--drivers/media/common/tuners/xc5000.h (renamed from drivers/media/dvb/frontends/xc5000.h)28
-rw-r--r--drivers/media/common/tuners/xc5000_priv.h (renamed from drivers/media/dvb/frontends/xc5000_priv.h)2
-rw-r--r--drivers/media/dvb/Kconfig4
-rw-r--r--drivers/media/dvb/b2c2/Kconfig2
-rw-r--r--drivers/media/dvb/b2c2/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c2
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig3
-rw-r--r--drivers/media/dvb/bt8xx/Makefile2
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig2
-rw-r--r--drivers/media/dvb/dvb-core/Kconfig34
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c28
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h2
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig27
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile2
-rw-r--r--drivers/media/dvb/frontends/Kconfig137
-rw-r--r--drivers/media/dvb/frontends/Makefile11
-rw-r--r--drivers/media/dvb/frontends/itd1000.c2
-rw-r--r--drivers/media/dvb/frontends/mt312.c9
-rw-r--r--drivers/media/dvb/frontends/mt312.h4
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig2
-rw-r--r--drivers/media/dvb/ttusb-dec/Kconfig1
-rw-r--r--drivers/media/video/Kconfig56
-rw-r--r--drivers/media/video/Makefile12
-rw-r--r--drivers/media/video/au0828/Kconfig5
-rw-r--r--drivers/media/video/au0828/Makefile2
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c6
-rw-r--r--drivers/media/video/bt8xx/Kconfig1
-rw-r--r--drivers/media/video/bt8xx/Makefile1
-rw-r--r--drivers/media/video/bt8xx/bttvp.h2
-rw-r--r--drivers/media/video/cs5345.c10
-rw-r--r--drivers/media/video/cs53l32a.c13
-rw-r--r--drivers/media/video/cx18/Kconfig23
-rw-r--r--drivers/media/video/cx18/Makefile11
-rw-r--r--drivers/media/video/cx18/cx18-audio.c73
-rw-r--r--drivers/media/video/cx18/cx18-audio.h26
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c361
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c879
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h318
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c120
-rw-r--r--drivers/media/video/cx18/cx18-av-vbi.c413
-rw-r--r--drivers/media/video/cx18/cx18-cards.c280
-rw-r--r--drivers/media/video/cx18/cx18-cards.h171
-rw-r--r--drivers/media/video/cx18/cx18-controls.c306
-rw-r--r--drivers/media/video/cx18/cx18-controls.h24
-rw-r--r--drivers/media/video/cx18/cx18-driver.c964
-rw-r--r--drivers/media/video/cx18/cx18-driver.h497
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c286
-rw-r--r--drivers/media/video/cx18/cx18-dvb.h25
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c713
-rw-r--r--drivers/media/video/cx18/cx18-fileops.h36
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c373
-rw-r--r--drivers/media/video/cx18/cx18-firmware.h25
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c99
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h24
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c431
-rw-r--r--drivers/media/video/cx18/cx18-i2c.h33
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c851
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.h30
-rw-r--r--drivers/media/video/cx18/cx18-irq.c179
-rw-r--r--drivers/media/video/cx18/cx18-irq.h37
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c372
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h73
-rw-r--r--drivers/media/video/cx18/cx18-queue.c272
-rw-r--r--drivers/media/video/cx18/cx18-queue.h55
-rw-r--r--drivers/media/video/cx18/cx18-scb.c121
-rw-r--r--drivers/media/video/cx18/cx18-scb.h285
-rw-r--r--drivers/media/video/cx18/cx18-streams.c569
-rw-r--r--drivers/media/video/cx18/cx18-streams.h33
-rw-r--r--drivers/media/video/cx18/cx18-vbi.c208
-rw-r--r--drivers/media/video/cx18/cx18-vbi.h26
-rw-r--r--drivers/media/video/cx18/cx18-version.h34
-rw-r--r--drivers/media/video/cx18/cx18-video.c45
-rw-r--r--drivers/media/video/cx18/cx18-video.h22
-rw-r--r--drivers/media/video/cx18/cx23418.h458
-rw-r--r--drivers/media/video/cx23885/Kconfig14
-rw-r--r--drivers/media/video/cx23885/Makefile1
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c36
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c7
-rw-r--r--drivers/media/video/cx25840/Kconfig1
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c10
-rw-r--r--drivers/media/video/cx88/Kconfig6
-rw-r--r--drivers/media/video/cx88/Makefile1
-rw-r--r--drivers/media/video/cx88/cx88-cards.c50
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c253
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c31
-rw-r--r--drivers/media/video/em28xx/Kconfig1
-rw-r--r--drivers/media/video/em28xx/Makefile1
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c1
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c2
-rw-r--r--drivers/media/video/ivtv/Kconfig2
-rw-r--r--drivers/media/video/ivtv/Makefile1
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c98
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c55
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c9
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c12
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c60
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.h6
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c12
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c13
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c3
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c2
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c8
-rw-r--r--drivers/media/video/m52790.c12
-rw-r--r--drivers/media/video/msp3400-driver.c19
-rw-r--r--drivers/media/video/mt9m001.c17
-rw-r--r--drivers/media/video/mt9v022.c19
-rw-r--r--drivers/media/video/pvrusb2/Kconfig55
-rw-r--r--drivers/media/video/pvrusb2/Makefile1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-dvb.c42
-rw-r--r--drivers/media/video/saa7115.c43
-rw-r--r--drivers/media/video/saa7127.c12
-rw-r--r--drivers/media/video/saa7134/Kconfig5
-rw-r--r--drivers/media/video/saa7134/Makefile1
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c260
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c140
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c42
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/video/saa7134/saa7134.h1
-rw-r--r--drivers/media/video/saa717x.c12
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c2
-rw-r--r--drivers/media/video/stk-webcam.c7
-rw-r--r--drivers/media/video/tcm825x.c10
-rw-r--r--drivers/media/video/tlv320aic23b.c9
-rw-r--r--drivers/media/video/tuner-core.c164
-rw-r--r--drivers/media/video/tvaudio.c15
-rw-r--r--drivers/media/video/tveeprom.c10
-rw-r--r--drivers/media/video/upd64031a.c9
-rw-r--r--drivers/media/video/upd64083.c9
-rw-r--r--drivers/media/video/usbvideo/vicam.c6
-rw-r--r--drivers/media/video/usbvision/Makefile1
-rw-r--r--drivers/media/video/v4l2-common.c5
-rw-r--r--drivers/media/video/vp27smpx.c12
-rw-r--r--drivers/media/video/wm8739.c10
-rw-r--r--drivers/media/video/wm8775.c10
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c2
-rw-r--r--drivers/media/video/zoran_device.c2
-rw-r--r--drivers/media/video/zoran_driver.c2
-rw-r--r--drivers/media/video/zoran_procfs.c7
-rw-r--r--drivers/message/i2o/i2o_block.c2
-rw-r--r--drivers/message/i2o/i2o_proc.c6
-rw-r--r--drivers/mfd/asic3.c6
-rw-r--r--drivers/mfd/htc-pasic3.c9
-rw-r--r--drivers/mfd/sm501.c4
-rw-r--r--drivers/misc/Kconfig21
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/eeepc-laptop.c666
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c5
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c17
-rw-r--r--drivers/misc/ibmasm/command.c6
-rw-r--r--drivers/misc/ibmasm/heartbeat.c6
-rw-r--r--drivers/misc/intel_menlow.c24
-rw-r--r--drivers/misc/ioc4.c20
-rw-r--r--drivers/misc/kgdbts.c77
-rw-r--r--drivers/misc/phantom.c34
-rw-r--r--drivers/misc/sgi-xp/xp.h305
-rw-r--r--drivers/misc/sgi-xp/xp_main.c44
-rw-r--r--drivers/misc/sgi-xp/xpc.h83
-rw-r--r--drivers/misc/sgi-xp/xpc_channel.c186
-rw-r--r--drivers/misc/sgi-xp/xpc_main.c60
-rw-r--r--drivers/misc/sgi-xp/xpc_partition.c78
-rw-r--r--drivers/misc/sgi-xp/xpnet.c22
-rw-r--r--drivers/misc/sony-laptop.c4
-rw-r--r--drivers/misc/thinkpad_acpi.c765
-rw-r--r--drivers/mmc/host/mmc_spi.c2
-rw-r--r--drivers/mmc/host/mmci.c18
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c14
-rw-r--r--drivers/mtd/devices/mtdram.c11
-rw-r--r--drivers/mtd/devices/phram.c13
-rw-r--r--drivers/mtd/devices/pmc551.c27
-rw-r--r--drivers/mtd/devices/slram.c15
-rw-r--r--drivers/mtd/maps/Kconfig9
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/mpc1211.c80
-rw-r--r--drivers/mtd/maps/uclinux.c6
-rw-r--r--drivers/mtd/mtdpart.c8
-rw-r--r--drivers/mtd/nand/at91_nand.c42
-rw-r--r--drivers/net/3c505.c30
-rw-r--r--drivers/net/3c505.h1
-rw-r--r--drivers/net/3c509.c47
-rw-r--r--drivers/net/3c515.c64
-rw-r--r--drivers/net/3c59x.c73
-rw-r--r--drivers/net/82596.c7
-rw-r--r--drivers/net/8390.c2
-rw-r--r--drivers/net/Kconfig17
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/apne.c3
-rw-r--r--drivers/net/appletalk/cops.c16
-rw-r--r--drivers/net/arm/Kconfig8
-rw-r--r--drivers/net/arm/Makefile1
-rw-r--r--drivers/net/arm/am79c961a.c10
-rw-r--r--drivers/net/arm/ixp4xx_eth.c1265
-rw-r--r--drivers/net/atlx/atl1.c157
-rw-r--r--drivers/net/atlx/atl1.h2
-rw-r--r--drivers/net/atlx/atlx.c2
-rw-r--r--drivers/net/atlx/atlx.h7
-rw-r--r--drivers/net/bfin_mac.c296
-rw-r--r--drivers/net/bfin_mac.h2
-rw-r--r--drivers/net/bnx2.c43
-rw-r--r--drivers/net/bnx2_fw2.h502
-rw-r--r--drivers/net/bonding/bond_main.c33
-rw-r--r--drivers/net/bonding/bond_sysfs.c16
-rw-r--r--drivers/net/cxgb3/adapter.h1
-rw-r--r--drivers/net/cxgb3/common.h1
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c44
-rw-r--r--drivers/net/cxgb3/regs.h8
-rw-r--r--drivers/net/cxgb3/sge.c29
-rw-r--r--drivers/net/cxgb3/t3_hw.c28
-rw-r--r--drivers/net/cxgb3/version.h2
-rw-r--r--drivers/net/dm9000.c37
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000e/defines.h10
-rw-r--r--drivers/net/e1000e/e1000.h7
-rw-r--r--drivers/net/e1000e/ethtool.c45
-rw-r--r--drivers/net/e1000e/hw.h22
-rw-r--r--drivers/net/e1000e/ich8lan.c83
-rw-r--r--drivers/net/e1000e/netdev.c330
-rw-r--r--drivers/net/e1000e/phy.c278
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eexpress.c11
-rw-r--r--drivers/net/ehea/ehea.h27
-rw-r--r--drivers/net/ehea/ehea_main.c25
-rw-r--r--drivers/net/ehea/ehea_qmr.c286
-rw-r--r--drivers/net/fec.c125
-rw-r--r--drivers/net/fec.h4
-rw-r--r--drivers/net/fec_mpc52xx.c120
-rw-r--r--drivers/net/fec_mpc52xx.h19
-rw-r--r--drivers/net/fs_enet/mii-fec.c3
-rw-r--r--drivers/net/gianfar.c34
-rw-r--r--drivers/net/gianfar.h4
-rw-r--r--drivers/net/gianfar_mii.c38
-rw-r--r--drivers/net/gianfar_mii.h3
-rw-r--r--drivers/net/gianfar_sysfs.c10
-rw-r--r--drivers/net/hamachi.c2
-rw-r--r--drivers/net/hamradio/6pack.c36
-rw-r--r--drivers/net/hamradio/mkiss.c15
-rw-r--r--drivers/net/ibmveth.c9
-rw-r--r--drivers/net/irda/irtty-sir.c95
-rw-r--r--drivers/net/irda/mcs7780.c2
-rw-r--r--drivers/net/irda/nsc-ircc.c6
-rw-r--r--drivers/net/irda/smsc-ircc2.c5
-rw-r--r--drivers/net/irda/stir4200.c2
-rw-r--r--drivers/net/irda/vlsi_ir.c5
-rw-r--r--drivers/net/mac89x0.c3
-rw-r--r--drivers/net/macmace.c3
-rw-r--r--drivers/net/macvlan.c2
-rw-r--r--drivers/net/mlx4/cq.c4
-rw-r--r--drivers/net/mlx4/mr.c8
-rw-r--r--drivers/net/mv643xx_eth.c160
-rw-r--r--drivers/net/myri10ge/myri10ge.c732
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h56
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp_gen_header.h39
-rw-r--r--drivers/net/niu.c64
-rw-r--r--drivers/net/niu.h9
-rw-r--r--drivers/net/pcnet32.c61
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/phy.c2
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/phy/smsc.c83
-rw-r--r--drivers/net/ppp_async.c9
-rw-r--r--drivers/net/ppp_generic.c1
-rw-r--r--drivers/net/ppp_synctty.c9
-rw-r--r--drivers/net/pppoe.c4
-rw-r--r--drivers/net/pppol2tp.c17
-rw-r--r--drivers/net/ps3_gelic_wireless.c2
-rw-r--r--drivers/net/r8169.c8
-rw-r--r--drivers/net/rionet.c16
-rw-r--r--drivers/net/s2io.c337
-rw-r--r--drivers/net/s2io.h82
-rw-r--r--drivers/net/sfc/Kconfig12
-rw-r--r--drivers/net/sfc/Makefile5
-rw-r--r--drivers/net/sfc/bitfield.h508
-rw-r--r--drivers/net/sfc/boards.c167
-rw-r--r--drivers/net/sfc/boards.h28
-rw-r--r--drivers/net/sfc/efx.c2210
-rw-r--r--drivers/net/sfc/efx.h67
-rw-r--r--drivers/net/sfc/enum.h99
-rw-r--r--drivers/net/sfc/ethtool.c717
-rw-r--r--drivers/net/sfc/ethtool.h27
-rw-r--r--drivers/net/sfc/falcon.c2724
-rw-r--r--drivers/net/sfc/falcon.h130
-rw-r--r--drivers/net/sfc/falcon_hwdefs.h1149
-rw-r--r--drivers/net/sfc/falcon_io.h243
-rw-r--r--drivers/net/sfc/falcon_xmac.c655
-rw-r--r--drivers/net/sfc/gmii.h195
-rw-r--r--drivers/net/sfc/i2c-direct.c381
-rw-r--r--drivers/net/sfc/i2c-direct.h91
-rw-r--r--drivers/net/sfc/mac.h33
-rw-r--r--drivers/net/sfc/mdio_10g.c360
-rw-r--r--drivers/net/sfc/mdio_10g.h254
-rw-r--r--drivers/net/sfc/net_driver.h909
-rw-r--r--drivers/net/sfc/phy.h48
-rw-r--r--drivers/net/sfc/rx.c884
-rw-r--r--drivers/net/sfc/rx.h29
-rw-r--r--drivers/net/sfc/selftest.c717
-rw-r--r--drivers/net/sfc/selftest.h50
-rw-r--r--drivers/net/sfc/sfe4001.c266
-rw-r--r--drivers/net/sfc/spi.h71
-rw-r--r--drivers/net/sfc/tenxpress.c517
-rw-r--r--drivers/net/sfc/tx.c1116
-rw-r--r--drivers/net/sfc/tx.h24
-rw-r--r--drivers/net/sfc/workarounds.h56
-rw-r--r--drivers/net/sfc/xenpack.h62
-rw-r--r--drivers/net/sfc/xfp_phy.c168
-rw-r--r--drivers/net/sis190.c136
-rw-r--r--drivers/net/sky2.h4
-rw-r--r--drivers/net/slip.c13
-rw-r--r--drivers/net/sun3lance.c3
-rw-r--r--drivers/net/tehuti.c2
-rw-r--r--drivers/net/tg3.c151
-rw-r--r--drivers/net/tg3.h15
-rw-r--r--drivers/net/tulip/de4x5.c35
-rw-r--r--drivers/net/tulip/de4x5.h2
-rw-r--r--drivers/net/tulip/tulip.h7
-rw-r--r--drivers/net/tulip/tulip_core.c10
-rw-r--r--drivers/net/tulip/uli526x.c38
-rw-r--r--drivers/net/ucc_geth.c278
-rw-r--r--drivers/net/ucc_geth.h48
-rw-r--r--drivers/net/ucc_geth_ethtool.c6
-rw-r--r--drivers/net/ucc_geth_mii.c4
-rw-r--r--drivers/net/usb/asix.c4
-rw-r--r--drivers/net/virtio_net.c96
-rw-r--r--drivers/net/wan/Kconfig4
-rw-r--r--drivers/net/wan/cosa.c14
-rw-r--r--drivers/net/wan/hdlc_ppp.c2
-rw-r--r--drivers/net/wan/hostess_sv11.c12
-rw-r--r--drivers/net/wan/lapbether.c1
-rw-r--r--drivers/net/wan/lmc/lmc_main.c1
-rw-r--r--drivers/net/wan/pc300_tty.c24
-rw-r--r--drivers/net/wan/sealevel.c1
-rw-r--r--drivers/net/wan/x25_asy.c279
-rw-r--r--drivers/net/wireless/airo.c94
-rw-r--r--drivers/net/wireless/ath5k/base.c8
-rw-r--r--drivers/net/wireless/atmel.c2
-rw-r--r--drivers/net/wireless/b43/b43.h4
-rw-r--r--drivers/net/wireless/b43/main.c53
-rw-r--r--drivers/net/wireless/b43legacy/main.c2
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c26
-rw-r--r--drivers/net/wireless/libertas/scan.c5
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00leds.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c33
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c2
-rw-r--r--drivers/net/wireless/strip.c66
-rw-r--r--drivers/net/wireless/wavelan.c4
-rw-r--r--drivers/net/wireless/wavelan_cs.c6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c10
-rw-r--r--drivers/net/xen-netfront.c2
-rw-r--r--drivers/net/yellowfin.c2
-rw-r--r--drivers/nubus/proc.c44
-rw-r--r--drivers/of/base.c3
-rw-r--r--drivers/oprofile/cpu_buffer.c2
-rw-r--r--drivers/oprofile/cpu_buffer.h2
-rw-r--r--drivers/parisc/asp.c2
-rw-r--r--drivers/parisc/ccio-dma.c50
-rw-r--r--drivers/parisc/dino.c14
-rw-r--r--drivers/parisc/gsc.c4
-rw-r--r--drivers/parisc/lasi.c2
-rw-r--r--drivers/parisc/lba_pci.c22
-rw-r--r--drivers/parisc/led.c2
-rw-r--r--drivers/parisc/sba_iommu.c56
-rw-r--r--drivers/parisc/wax.c2
-rw-r--r--drivers/parport/ieee1284.c4
-rw-r--r--drivers/parport/parport_gsc.c4
-rw-r--r--drivers/parport/parport_pc.c12
-rw-r--r--drivers/pci/hotplug/pciehp.h17
-rw-r--r--drivers/pci/hotplug/pciehp_core.c19
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c46
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c565
-rw-r--r--drivers/pci/hotplug/shpchp_core.c11
-rw-r--r--drivers/pci/intel-iommu.c6
-rw-r--r--drivers/pci/msi.c56
-rw-r--r--drivers/pci/pci-acpi.c109
-rw-r--r--drivers/pci/pci-driver.c2
-rw-r--r--drivers/pci/pcie/Kconfig2
-rw-r--r--drivers/pci/probe.c32
-rw-r--r--drivers/pci/proc.c15
-rw-r--r--drivers/pci/quirks.c4
-rw-r--r--drivers/pcmcia/au1000_db1x00.c6
-rw-r--r--drivers/pcmcia/au1000_generic.c11
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c14
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c2
-rw-r--r--drivers/pcmcia/cardbus.c2
-rw-r--r--drivers/pcmcia/cistpl.c39
-rw-r--r--drivers/pcmcia/cs.c13
-rw-r--r--drivers/pcmcia/cs_internal.h3
-rw-r--r--drivers/pcmcia/ds.c2
-rw-r--r--drivers/pcmcia/i82092.c6
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c4
-rw-r--r--drivers/pcmcia/pd6729.c6
-rw-r--r--drivers/pcmcia/pxa2xx_lubbock.c8
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c4
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c2
-rw-r--r--drivers/pcmcia/sa1100_assabet.c4
-rw-r--r--drivers/pcmcia/sa1100_badge4.c8
-rw-r--r--drivers/pcmcia/sa1100_cerf.c2
-rw-r--r--drivers/pcmcia/sa1100_jornada720.c4
-rw-r--r--drivers/pcmcia/sa1100_neponset.c4
-rw-r--r--drivers/pcmcia/sa1100_shannon.c8
-rw-r--r--drivers/pcmcia/sa1100_simpad.c2
-rw-r--r--drivers/pcmcia/soc_common.c17
-rw-r--r--drivers/pcmcia/soc_common.h1
-rw-r--r--drivers/pcmcia/socket_sysfs.c52
-rw-r--r--drivers/pnp/base.h75
-rw-r--r--drivers/pnp/card.c55
-rw-r--r--drivers/pnp/core.c46
-rw-r--r--drivers/pnp/driver.c28
-rw-r--r--drivers/pnp/interface.c111
-rw-r--r--drivers/pnp/isapnp/Makefile4
-rw-r--r--drivers/pnp/isapnp/core.c340
-rw-r--r--drivers/pnp/isapnp/proc.c9
-rw-r--r--drivers/pnp/manager.c356
-rw-r--r--drivers/pnp/pnpacpi/Makefile4
-rw-r--r--drivers/pnp/pnpacpi/core.c92
-rw-r--r--drivers/pnp/pnpacpi/pnpacpi.h8
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c589
-rw-r--r--drivers/pnp/pnpbios/Makefile4
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c1
-rw-r--r--drivers/pnp/pnpbios/core.c31
-rw-r--r--drivers/pnp/pnpbios/pnpbios.h140
-rw-r--r--drivers/pnp/pnpbios/proc.c6
-rw-r--r--drivers/pnp/pnpbios/rsparser.c328
-rw-r--r--drivers/pnp/quirks.c146
-rw-r--r--drivers/pnp/resource.c363
-rw-r--r--drivers/pnp/support.c63
-rw-r--r--drivers/pnp/system.c21
-rw-r--r--drivers/power/ds2760_battery.c4
-rw-r--r--drivers/power/olpc_battery.c2
-rw-r--r--drivers/power/pda_power.c11
-rw-r--r--drivers/power/pmu_battery.c2
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/power_supply_leds.c4
-rw-r--r--drivers/ps3/ps3-lpm.c1
-rw-r--r--drivers/ps3/ps3-sys-manager.c7
-rw-r--r--drivers/rapidio/Kconfig8
-rw-r--r--drivers/rapidio/rio-access.c10
-rw-r--r--drivers/rapidio/rio-scan.c55
-rw-r--r--drivers/rapidio/rio-sysfs.c3
-rw-r--r--drivers/rapidio/rio.c2
-rw-r--r--drivers/rapidio/rio.h9
-rw-r--r--drivers/rtc/rtc-bfin.c2
-rw-r--r--drivers/rtc/rtc-cmos.c7
-rw-r--r--drivers/rtc/rtc-ds1307.c66
-rw-r--r--drivers/rtc/rtc-ds1374.c10
-rw-r--r--drivers/rtc/rtc-ds1511.c4
-rw-r--r--drivers/rtc/rtc-isl1208.c9
-rw-r--r--drivers/rtc/rtc-lib.c2
-rw-r--r--drivers/rtc/rtc-m41t80.c84
-rw-r--r--drivers/rtc/rtc-pcf8563.c10
-rw-r--r--drivers/rtc/rtc-proc.c8
-rw-r--r--drivers/rtc/rtc-rs5c372.c27
-rw-r--r--drivers/rtc/rtc-s35390a.c12
-rw-r--r--drivers/rtc/rtc-sh.c14
-rw-r--r--drivers/rtc/rtc-x1205.c10
-rw-r--r--drivers/s390/block/dasd.c5
-rw-r--r--drivers/s390/block/dasd_devmap.c10
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/block/dasd_proc.c16
-rw-r--r--drivers/s390/char/con3215.c5
-rw-r--r--drivers/s390/char/sclp_config.c17
-rw-r--r--drivers/s390/char/sclp_tty.c4
-rw-r--r--drivers/s390/char/sclp_vt220.c6
-rw-r--r--drivers/s390/char/tape_core.c31
-rw-r--r--drivers/s390/char/tape_proc.c9
-rw-r--r--drivers/s390/char/tty3270.c14
-rw-r--r--drivers/s390/char/vmlogrdr.c2
-rw-r--r--drivers/s390/cio/blacklist.c329
-rw-r--r--drivers/s390/cio/ccwgroup.c103
-rw-r--r--drivers/s390/cio/cio.c48
-rw-r--r--drivers/s390/cio/cio.h5
-rw-r--r--drivers/s390/cio/cio_debug.h6
-rw-r--r--drivers/s390/cio/cmf.c11
-rw-r--r--drivers/s390/cio/css.c14
-rw-r--r--drivers/s390/cio/device.c42
-rw-r--r--drivers/s390/cio/device_fsm.c54
-rw-r--r--drivers/s390/cio/device_id.c4
-rw-r--r--drivers/s390/cio/device_ops.c2
-rw-r--r--drivers/s390/cio/device_pgid.c24
-rw-r--r--drivers/s390/cio/qdio.c12
-rw-r--r--drivers/s390/kvm/kvm_virtio.c23
-rw-r--r--drivers/s390/net/cu3088.c20
-rw-r--r--drivers/s390/net/lcs.c3
-rw-r--r--drivers/s390/net/netiucv.c3
-rw-r--r--drivers/s390/net/qeth_core.h50
-rw-r--r--drivers/s390/net/qeth_core_main.c200
-rw-r--r--drivers/s390/net/qeth_l2_main.c30
-rw-r--r--drivers/s390/net/qeth_l3.h3
-rw-r--r--drivers/s390/net/qeth_l3_main.c30
-rw-r--r--drivers/s390/s390mach.c3
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/sbus/char/bpp.c2
-rw-r--r--drivers/sbus/char/cpwatchdog.c2
-rw-r--r--drivers/sbus/char/uctrl.c4
-rw-r--r--drivers/scsi/53c700.c6
-rw-r--r--drivers/scsi/Kconfig4
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/aacraid/aachba.c133
-rw-r--r--drivers/scsi/aacraid/aacraid.h28
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/commsup.c34
-rw-r--r--drivers/scsi/aacraid/linit.c22
-rw-r--r--drivers/scsi/aha152x.c8
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c6
-rw-r--r--drivers/scsi/constants.c10
-rw-r--r--drivers/scsi/dpt/dpti_ioctl.h16
-rw-r--r--drivers/scsi/dpt/dptsig.h8
-rw-r--r--drivers/scsi/dpt/sys_info.h4
-rw-r--r--drivers/scsi/dpt_i2o.c718
-rw-r--r--drivers/scsi/dpti.h28
-rw-r--r--drivers/scsi/gdth.c53
-rw-r--r--drivers/scsi/hptiop.c6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c7
-rw-r--r--drivers/scsi/ibmvscsi/viosrp.h9
-rw-r--r--drivers/scsi/initio.c2
-rw-r--r--drivers/scsi/ipr.c2
-rw-r--r--drivers/scsi/libiscsi.c29
-rw-r--r--drivers/scsi/megaraid.c6
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c17
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h1
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c13
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h6
-rw-r--r--drivers/scsi/mvsas.c4
-rw-r--r--drivers/scsi/ncr53c8xx.c2
-rw-r--r--drivers/scsi/qla1280.c8
-rw-r--r--drivers/scsi/scsi.c23
-rw-r--r--drivers/scsi/scsi_debug.c2
-rw-r--r--drivers/scsi/scsi_devinfo.c77
-rw-r--r--drivers/scsi/scsi_error.c16
-rw-r--r--drivers/scsi/scsi_lib.c38
-rw-r--r--drivers/scsi/scsi_proc.c4
-rw-r--r--drivers/scsi/scsi_scan.c2
-rw-r--r--drivers/scsi/scsi_tgt_lib.c2
-rw-r--r--drivers/scsi/scsi_transport_sas.c3
-rw-r--r--drivers/scsi/sd.c1
-rw-r--r--drivers/scsi/sg.c12
-rw-r--r--drivers/scsi/u14-34f.c6
-rw-r--r--drivers/serial/68328serial.c21
-rw-r--r--drivers/serial/68360serial.c28
-rw-r--r--drivers/serial/8250.c3
-rw-r--r--drivers/serial/8250_early.c4
-rw-r--r--drivers/serial/8250_pci.c14
-rw-r--r--drivers/serial/Kconfig49
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/bfin_5xx.c102
-rw-r--r--drivers/serial/bfin_sport_uart.c614
-rw-r--r--drivers/serial/bfin_sport_uart.h63
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/crisv10.c31
-rw-r--r--drivers/serial/ioc3_serial.c36
-rw-r--r--drivers/serial/ioc4_serial.c32
-rw-r--r--drivers/serial/jsm/jsm.h1
-rw-r--r--drivers/serial/jsm/jsm_driver.c6
-rw-r--r--drivers/serial/kgdboc.c6
-rw-r--r--drivers/serial/mcfserial.c23
-rw-r--r--drivers/serial/mpc52xx_uart.c4
-rw-r--r--drivers/serial/netx-serial.c1
-rw-r--r--drivers/serial/s3c2410.c13
-rw-r--r--drivers/serial/sa1100.c4
-rw-r--r--drivers/serial/serial_core.c57
-rw-r--r--drivers/serial/sh-sci.c34
-rw-r--r--drivers/serial/sh-sci.h27
-rw-r--r--drivers/serial/sn_console.c2
-rw-r--r--drivers/serial/sunhv.c2
-rw-r--r--drivers/serial/sunsab.c2
-rw-r--r--drivers/serial/sunsu.c2
-rw-r--r--drivers/serial/sunzilog.c2
-rw-r--r--drivers/serial/uartlite.c2
-rw-r--r--drivers/serial/ucc_uart.c4
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/atmel_spi.c29
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c2
-rw-r--r--drivers/spi/pxa2xx_spi.c2
-rw-r--r--drivers/spi/spi_bfin5xx.c7
-rw-r--r--drivers/spi/spi_mpc83xx.c411
-rw-r--r--drivers/spi/spi_s3c24xx.c6
-rw-r--r--drivers/thermal/Kconfig4
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/thermal_sys.c (renamed from drivers/thermal/thermal.c)165
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/Kconfig4
-rw-r--r--drivers/usb/atm/ueagle-atm.c48
-rw-r--r--drivers/usb/c67x00/Makefile9
-rw-r--r--drivers/usb/c67x00/c67x00-drv.c243
-rw-r--r--drivers/usb/c67x00/c67x00-hcd.c412
-rw-r--r--drivers/usb/c67x00/c67x00-hcd.h133
-rw-r--r--drivers/usb/c67x00/c67x00-ll-hpi.c481
-rw-r--r--drivers/usb/c67x00/c67x00-sched.c1170
-rw-r--r--drivers/usb/c67x00/c67x00.h294
-rw-r--r--drivers/usb/class/cdc-acm.c5
-rw-r--r--drivers/usb/core/endpoint.c11
-rw-r--r--drivers/usb/core/inode.c4
-rw-r--r--drivers/usb/core/message.c5
-rw-r--r--drivers/usb/core/sysfs.c137
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/core/usb.h4
-rw-r--r--drivers/usb/gadget/Kconfig20
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/amd5536udc.c10
-rw-r--r--drivers/usb/gadget/at91_udc.c11
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c48
-rw-r--r--drivers/usb/gadget/ether.c8
-rw-r--r--drivers/usb/gadget/file_storage.c25
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c7
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2403
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h495
-rw-r--r--drivers/usb/gadget/rndis.c40
-rw-r--r--drivers/usb/gadget/serial.c800
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c370
-rw-r--r--drivers/usb/host/Kconfig39
-rw-r--r--drivers/usb/host/Makefile4
-rw-r--r--drivers/usb/host/ehci-hub.c2
-rw-r--r--drivers/usb/host/isp1760-hcd.c2231
-rw-r--r--drivers/usb/host/isp1760-hcd.h206
-rw-r--r--drivers/usb/host/isp1760-if.c298
-rw-r--r--drivers/usb/host/ohci-hub.c6
-rw-r--r--drivers/usb/host/ohci-sm501.c2
-rw-r--r--drivers/usb/host/sl811-hcd.c10
-rw-r--r--drivers/usb/host/uhci-hcd.c74
-rw-r--r--drivers/usb/host/uhci-hcd.h5
-rw-r--r--drivers/usb/misc/ldusb.c32
-rw-r--r--drivers/usb/misc/usbtest.c281
-rw-r--r--drivers/usb/serial/Kconfig9
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/aircable.c98
-rw-r--r--drivers/usb/serial/airprime.c63
-rw-r--r--drivers/usb/serial/ark3116.c54
-rw-r--r--drivers/usb/serial/ch341.c2
-rw-r--r--drivers/usb/serial/cp2101.c1
-rw-r--r--drivers/usb/serial/digi_acceleport.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.h11
-rw-r--r--drivers/usb/serial/iuu_phoenix.c6
-rw-r--r--drivers/usb/serial/mos7840.c5
-rw-r--r--drivers/usb/serial/moto_modem.c70
-rw-r--r--drivers/usb/serial/option.c9
-rw-r--r--drivers/usb/serial/usb-serial.c129
-rw-r--r--drivers/usb/serial/whiteheat.c4
-rw-r--r--drivers/usb/storage/Kconfig3
-rw-r--r--drivers/usb/storage/cypress_atacb.c2
-rw-r--r--drivers/usb/storage/isd200.c2
-rw-r--r--drivers/usb/storage/libusual.c2
-rw-r--r--drivers/usb/storage/onetouch.c4
-rw-r--r--drivers/usb/storage/unusual_devs.h81
-rw-r--r--drivers/usb/storage/usb.c3
-rw-r--r--drivers/video/Kconfig10
-rw-r--r--drivers/video/amifb.c4
-rw-r--r--drivers/video/atmel_lcdfb.c11
-rw-r--r--drivers/video/bw2.c8
-rw-r--r--drivers/video/cg14.c5
-rw-r--r--drivers/video/cg3.c8
-rw-r--r--drivers/video/cg6.c6
-rw-r--r--drivers/video/clps711xfb.c2
-rw-r--r--drivers/video/console/fbcon.c39
-rw-r--r--drivers/video/console/mdacon.c2
-rw-r--r--drivers/video/console/sticon.c4
-rw-r--r--drivers/video/console/vgacon.c4
-rw-r--r--drivers/video/dnfb.c3
-rw-r--r--drivers/video/ffb.c7
-rw-r--r--drivers/video/geode/lxfb_ops.c22
-rw-r--r--drivers/video/hpfb.c2
-rw-r--r--drivers/video/leo.c7
-rw-r--r--drivers/video/logo/Kconfig10
-rw-r--r--drivers/video/logo/Makefile2
-rw-r--r--drivers/video/logo/logo.c10
-rw-r--r--drivers/video/logo/logo_blackfin_clut224.ppm1127
-rw-r--r--drivers/video/logo/logo_blackfin_vga16.ppm1127
-rw-r--r--drivers/video/matrox/matroxfb_misc.c28
-rw-r--r--drivers/video/metronomefb.c9
-rw-r--r--drivers/video/p9100.c7
-rw-r--r--drivers/video/pnx4008/pnxrgbfb.c11
-rw-r--r--drivers/video/pxafb.c1302
-rw-r--r--drivers/video/pxafb.h70
-rw-r--r--drivers/video/sbuslib.c9
-rw-r--r--drivers/video/sbuslib.h5
-rw-r--r--drivers/video/sunxvr2500.c3
-rw-r--r--drivers/video/sunxvr500.c3
-rw-r--r--drivers/video/tcx.c25
-rw-r--r--drivers/video/tridentfb.c25
-rw-r--r--drivers/virtio/virtio.c38
-rw-r--r--drivers/virtio/virtio_balloon.c12
-rw-r--r--drivers/virtio/virtio_pci.c34
-rw-r--r--drivers/virtio/virtio_ring.c5
-rw-r--r--drivers/w1/w1_log.h2
-rw-r--r--drivers/zorro/proc.c81
1226 files changed, 72805 insertions, 21934 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 80f0ec91e2cf..59f33fa6af3e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -84,6 +84,8 @@ source "drivers/memstick/Kconfig"
source "drivers/leds/Kconfig"
+source "drivers/accessibility/Kconfig"
+
source "drivers/infiniband/Kconfig"
source "drivers/edac/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index e5e394a7e6c0..f65deda72d61 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
+obj-$(CONFIG_ACCESSIBILITY) += accessibility/
obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_MCA) += mca/
diff --git a/drivers/accessibility/Kconfig b/drivers/accessibility/Kconfig
new file mode 100644
index 000000000000..ef3b65bfdd0a
--- /dev/null
+++ b/drivers/accessibility/Kconfig
@@ -0,0 +1,33 @@
+menuconfig ACCESSIBILITY
+ bool "Accessibility support"
+ ---help---
+ Accessibility handles all special kinds of hardware devices or
+ software adapters which help people with disabilities (e.g.
+ blindness) to use computers.
+
+ That includes braille devices, speech synthesis, keyboard
+ remapping, etc.
+
+ Say Y here to get to see options for accessibility.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+ If unsure, say N.
+
+if ACCESSIBILITY
+config A11Y_BRAILLE_CONSOLE
+ bool "Console on braille device"
+ depends on VT
+ depends on SERIAL_CORE_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl,ttyS0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # ACCESSIBILITY
diff --git a/drivers/accessibility/Makefile b/drivers/accessibility/Makefile
new file mode 100644
index 000000000000..72b01a46546f
--- /dev/null
+++ b/drivers/accessibility/Makefile
@@ -0,0 +1 @@
+obj-y += braille/
diff --git a/drivers/accessibility/braille/Makefile b/drivers/accessibility/braille/Makefile
new file mode 100644
index 000000000000..2e9f16c91347
--- /dev/null
+++ b/drivers/accessibility/braille/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
new file mode 100644
index 000000000000..0a5f6b2114c5
--- /dev/null
+++ b/drivers/accessibility/braille/braille_console.c
@@ -0,0 +1,397 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.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 the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("samuel.thibault@ens-lyon.org");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+
+static void beep(unsigned int freq)
+{
+ if (sound)
+ kd_mksound(freq, HZ/10);
+}
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i = 0; i < WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum |= 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ braille_co->write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i < WIDTH; i++) {
+ u16 glyph = screen_glyph(vc,
+ 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch (val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ if (vc->vc_num != fg_console)
+ break;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1],
+ (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Called from printk.c when console=brl is given
+ */
+
+int braille_register_console(struct console *console, int index,
+ char *console_options, char *braille_options)
+{
+ int ret;
+ if (!console_options)
+ /* Only support VisioBraille for now */
+ console_options = "57600o8";
+ if (braille_co)
+ return -ENODEV;
+ if (console->setup) {
+ ret = console->setup(console, console_options);
+ if (ret != 0)
+ return ret;
+ }
+ console->flags |= CON_ENABLED;
+ console->index = index;
+ braille_co = console;
+ return 0;
+}
+
+int braille_unregister_console(struct console *console)
+{
+ if (braille_co != console)
+ return -EINVAL;
+ braille_co = NULL;
+ return 0;
+}
+
+static int __init braille_init(void)
+{
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+
+console_initcall(braille_init);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b4f5e8542829..c52fca833268 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -140,6 +140,7 @@ config ACPI_VIDEO
tristate "Video"
depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
depends on INPUT
+ select THERMAL
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -151,6 +152,7 @@ config ACPI_VIDEO
config ACPI_FAN
tristate "Fan"
+ select THERMAL
default y
help
This driver adds support for ACPI fan devices, allowing user-mode
@@ -172,6 +174,7 @@ config ACPI_BAY
config ACPI_PROCESSOR
tristate "Processor"
+ select THERMAL
default y
help
This driver installs ACPI as the idle handler for Linux, and uses
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 43a95e5640de..5b73f6a2cd86 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -92,6 +92,7 @@ struct acpi_ac {
#ifdef CONFIG_ACPI_PROCFS_POWER
static const struct file_operations acpi_ac_fops = {
+ .owner = THIS_MODULE,
.open = acpi_ac_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -195,16 +196,11 @@ static int acpi_ac_add_fs(struct acpi_device *device)
}
/* 'state' [R] */
- entry = create_proc_entry(ACPI_AC_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_AC_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_ac_fops, acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_ac_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index d5729d5dc190..b1c723f9f58d 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -741,15 +741,13 @@ static int acpi_battery_add_fs(struct acpi_device *device)
}
for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
- entry = create_proc_entry(acpi_battery_file[i].name,
- acpi_battery_file[i].mode, acpi_device_dir(device));
+ entry = proc_create_data(acpi_battery_file[i].name,
+ acpi_battery_file[i].mode,
+ acpi_device_dir(device),
+ &acpi_battery_file[i].ops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_file[i].ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
}
return 0;
}
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 1fa86811b8ee..d2fc94161848 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -201,6 +201,7 @@ static int is_ejectable_bay(acpi_handle handle)
return 0;
}
+#if 0
/**
* eject_removable_drive - try to eject this drive
* @dev : the device structure of the drive
@@ -225,6 +226,7 @@ int eject_removable_drive(struct device *dev)
return 0;
}
EXPORT_SYMBOL_GPL(eject_removable_drive);
+#endif /* 0 */
static int acpi_bay_add_fs(struct bay *bay)
{
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 2d1955c11833..a6dbcf4d9ef5 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -35,6 +35,7 @@
#ifdef CONFIG_X86
#include <asm/mpspec.h>
#endif
+#include <linux/pci.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -784,6 +785,7 @@ static int __init acpi_init(void)
result = acpi_bus_init();
if (!result) {
+ pci_mmcfg_late_init();
if (!(pm_flags & PM_APM))
pm_flags |= PM_ACPI;
else {
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 6c5da83cdb68..1dfec413588c 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -102,6 +102,7 @@ struct acpi_button {
};
static const struct file_operations acpi_button_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_button_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -109,6 +110,7 @@ static const struct file_operations acpi_button_info_fops = {
};
static const struct file_operations acpi_button_state_fops = {
+ .owner = THIS_MODULE,
.open = acpi_button_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -207,27 +209,21 @@ static int acpi_button_add_fs(struct acpi_device *device)
acpi_device_dir(device)->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_BUTTON_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_button_info_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_button_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* show lid state [R] */
if (button->type == ACPI_BUTTON_TYPE_LID) {
- entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_BUTTON_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_button_state_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_button_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
}
return 0;
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index f049639bac35..c78078315be9 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,12 +89,16 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
ACPI_FUNCTION_TRACE(ds_create_buffer_field);
- /* Get the name_string argument */
-
+ /*
+ * Get the name_string argument (name of the new buffer_field)
+ */
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
+ /* For create_field, name is the 4th argument */
+
arg = acpi_ps_get_arg(op, 3);
} else {
- /* Create Bit/Byte/Word/Dword field */
+ /* For all other create_xXXField operators, name is the 3rd argument */
arg = acpi_ps_get_arg(op, 2);
}
@@ -107,26 +111,30 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
node = walk_state->deferred_node;
status = AE_OK;
} else {
- /*
- * During the load phase, we want to enter the name of the field into
- * the namespace. During the execute phase (when we evaluate the size
- * operand), we want to lookup the name
- */
- if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
- } else {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
- ACPI_NS_ERROR_IF_FOUND;
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ return_ACPI_STATUS(AE_AML_INTERNAL);
}
- /*
- * Enter the name_string into the namespace
- */
+ /* Creating new namespace node, should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
+ /* Enter the name_string into the namespace */
+
status =
acpi_ns_lookup(walk_state->scope_info,
arg->common.value.string, ACPI_TYPE_ANY,
ACPI_IMODE_LOAD_PASS1, flags, walk_state,
- &(node));
+ &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
return_ACPI_STATUS(status);
@@ -136,13 +144,13 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
/*
* 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
+ * so we can get it again at the end of this scope.
*/
op->common.node = node;
/*
* If there is no object attached to the node, this node was just created
- * and we need to create the field object. Otherwise, this was a lookup
+ * and we need to create the field object. Otherwise, this was a lookup
* of an existing node and we don't want to create the field object again.
*/
obj_desc = acpi_ns_get_attached_object(node);
@@ -164,9 +172,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
}
/*
- * Remember location in AML stream of the field unit
- * opcode and operands -- since the buffer and index
- * operands must be evaluated.
+ * Remember location in AML stream of the field unit opcode and operands --
+ * since the buffer and index operands must be evaluated.
*/
second_desc = obj_desc->common.next_object;
second_desc->extra.aml_start = op->named.data;
@@ -261,7 +268,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
case AML_INT_NAMEDFIELD_OP:
- /* Lookup the name */
+ /* Lookup the name, it should already exist */
status = acpi_ns_lookup(walk_state->scope_info,
(char *)&arg->named.name,
@@ -272,20 +279,23 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
status);
- if (status != AE_ALREADY_EXISTS) {
- return_ACPI_STATUS(status);
- }
-
- /* Already exists, ignore error */
+ return_ACPI_STATUS(status);
} else {
arg->common.node = info->field_node;
info->field_bit_length = arg->common.value.size;
- /* Create and initialize an object for the new Field Node */
-
- status = acpi_ex_prep_field_value(info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * If there is no object attached to the node, this node was
+ * just created and we need to create the field object.
+ * Otherwise, this was a lookup of an existing node and we
+ * don't want to create the field object again.
+ */
+ if (!acpi_ns_get_attached_object
+ (info->field_node)) {
+ status = acpi_ex_prep_field_value(info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
@@ -399,9 +409,27 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
union acpi_parse_object *arg = NULL;
struct acpi_namespace_node *node;
u8 type = 0;
+ u32 flags;
ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) {
+
+ /* bank_field Op is deferred, just return OK */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ /*
+ * Get the field_list argument for this opcode. This is the start of the
+ * list of field elements.
+ */
switch (walk_state->opcode) {
case AML_FIELD_OP:
arg = acpi_ps_get_arg(op, 2);
@@ -422,20 +450,33 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ if (!arg) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
+
+ /* Creating new namespace node(s), should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node(s) temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
/*
* Walk the list of entries in the field_list
*/
while (arg) {
-
- /* Ignore OFFSET and ACCESSAS terms here */
-
+ /*
+ * Ignore OFFSET and ACCESSAS terms here; we are only interested in the
+ * field names in order to enter them into the namespace.
+ */
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
status = acpi_ns_lookup(walk_state->scope_info,
- (char *)&arg->named.name,
- type, ACPI_IMODE_LOAD_PASS1,
- ACPI_NS_NO_UPSEARCH |
- ACPI_NS_DONT_OPEN_SCOPE |
- ACPI_NS_ERROR_IF_FOUND,
+ (char *)&arg->named.name, type,
+ ACPI_IMODE_LOAD_PASS1, flags,
walk_state, &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
@@ -452,7 +493,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
arg->common.node = node;
}
- /* Move to next field in the list */
+ /* Get the next field element in the list */
arg = arg->common.next;
}
@@ -466,7 +507,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
*
* PARAMETERS: Op - Op containing the Field definition and args
* region_node - Object for the containing Operation Region
- * ` walk_state - Current method state
+ * walk_state - Current method state
*
* RETURN: Status
*
@@ -513,36 +554,13 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
return_ACPI_STATUS(status);
}
- /* Third arg is the bank_value */
-
- /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
-
+ /*
+ * Third arg is the bank_value
+ * This arg is a term_arg, not a constant
+ * It will be evaluated later, by acpi_ds_eval_bank_field_operands
+ */
arg = arg->common.next;
- /* 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 */
arg = arg->common.next;
@@ -553,8 +571,17 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
info.region_node = region_node;
- status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+ /*
+ * Use Info.data_register_node to store bank_field Op
+ * It's safe because data_register_node will never be used when create bank field
+ * We store aml_start and aml_length in the bank_field Op for late evaluation
+ * Used in acpi_ex_prep_field_value(Info)
+ *
+ * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?
+ */
+ info.data_register_node = (struct acpi_namespace_node *)op;
+ status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index af923c388520..610b1ee102b0 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 1cbe61905824..e48a3ea03117 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,6 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
#include <acpi/amlcode.h>
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
@@ -102,7 +101,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
walk_state->opcode,
walk_state->aml_offset,
NULL);
- (void)acpi_ex_enter_interpreter();
+ acpi_ex_enter_interpreter();
}
#ifdef ACPI_DISASSEMBLER
if (ACPI_FAILURE(status)) {
@@ -232,9 +231,9 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
* recursive call.
*/
if (!walk_state ||
- !obj_desc->method.mutex->mutex.owner_thread ||
- (walk_state->thread !=
- obj_desc->method.mutex->mutex.owner_thread)) {
+ !obj_desc->method.mutex->mutex.thread_id ||
+ (walk_state->thread->thread_id !=
+ obj_desc->method.mutex->mutex.thread_id)) {
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
@@ -254,8 +253,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
original_sync_level =
walk_state->thread->current_sync_level;
- obj_desc->method.mutex->mutex.owner_thread =
- walk_state->thread;
+ obj_desc->method.mutex->mutex.thread_id =
+ walk_state->thread->thread_id;
walk_state->thread->current_sync_level =
obj_desc->method.sync_level;
} else {
@@ -535,8 +534,6 @@ void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
struct acpi_walk_state *walk_state)
{
- struct acpi_namespace_node *method_node;
- acpi_status status;
ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
@@ -551,34 +548,26 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
/* Delete all arguments and locals */
acpi_ds_method_data_delete_all(walk_state);
- }
- /*
- * If method is serialized, release the mutex and restore the
- * current sync level for this thread
- */
- if (method_desc->method.mutex) {
+ /*
+ * If method is serialized, release the mutex and restore the
+ * current sync level for this thread
+ */
+ if (method_desc->method.mutex) {
- /* Acquisition Depth handles recursive calls */
+ /* Acquisition Depth handles recursive calls */
- method_desc->method.mutex->mutex.acquisition_depth--;
- if (!method_desc->method.mutex->mutex.acquisition_depth) {
- walk_state->thread->current_sync_level =
- method_desc->method.mutex->mutex.
- original_sync_level;
+ method_desc->method.mutex->mutex.acquisition_depth--;
+ if (!method_desc->method.mutex->mutex.acquisition_depth) {
+ walk_state->thread->current_sync_level =
+ method_desc->method.mutex->mutex.
+ original_sync_level;
- acpi_os_release_mutex(method_desc->method.mutex->mutex.
- os_mutex);
- method_desc->method.mutex->mutex.owner_thread = NULL;
+ acpi_os_release_mutex(method_desc->method.
+ mutex->mutex.os_mutex);
+ method_desc->method.mutex->mutex.thread_id = 0;
+ }
}
- }
-
- if (walk_state) {
- /*
- * Delete any objects created by this method during execution.
- * The method Node is stored in the walk state
- */
- method_node = walk_state->method_node;
/*
* Delete any namespace objects created anywhere within
@@ -620,7 +609,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
*/
if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
&& (!method_desc->method.mutex)) {
- status = acpi_ds_create_method_mutex(method_desc);
+ (void)acpi_ds_create_method_mutex(method_desc);
}
/* No more threads, we can free the owner_id */
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index ba4626e06a5e..13c43eac35db 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 954ac8ce958a..1022e38994c2 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -157,7 +157,9 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
* will remain as named references. This behavior is not described
* in the ACPI spec, but it appears to be an oversight.
*/
- obj_desc = (union acpi_operand_object *)op->common.node;
+ obj_desc =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ op->common.node);
status =
acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
@@ -172,7 +174,19 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
switch (op->common.node->type) {
/*
* For these types, we need the actual node, not the subobject.
- * However, the subobject got an extra reference count above.
+ * However, the subobject did not get an extra reference count above.
+ *
+ * TBD: should ex_resolve_node_to_value be changed to fix this?
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_THERMAL:
+
+ acpi_ut_add_reference(op->common.node->object);
+
+ /*lint -fallthrough */
+ /*
+ * For these types, we need the actual node, not the subobject.
+ * The subobject got an extra reference count in ex_resolve_node_to_value.
*/
case ACPI_TYPE_MUTEX:
case ACPI_TYPE_METHOD:
@@ -180,25 +194,15 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_EVENT:
case ACPI_TYPE_REGION:
- case ACPI_TYPE_DEVICE:
- case ACPI_TYPE_THERMAL:
- obj_desc =
- (union acpi_operand_object *)op->common.
- node;
+ /* We will create a reference object for these types below */
break;
default:
- break;
- }
-
- /*
- * If above resolved to an operand object, we are done. Otherwise,
- * we have a NS node, we must create the package entry as a named
- * reference.
- */
- if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) !=
- ACPI_DESC_TYPE_NAMED) {
+ /*
+ * All other types - the node was resolved to an actual
+ * object, we are done.
+ */
goto exit;
}
}
@@ -223,7 +227,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
exit:
*obj_desc_ptr = obj_desc;
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -369,7 +373,9 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
acpi_status status = AE_OK;
- acpi_native_uint i;
+ unsigned i;
+ u16 index;
+ u16 reference_count;
ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);
@@ -447,13 +453,60 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
package.
elements[i]);
}
+
+ if (*obj_desc_ptr) {
+
+ /* Existing package, get existing reference count */
+
+ reference_count =
+ (*obj_desc_ptr)->common.reference_count;
+ if (reference_count > 1) {
+
+ /* Make new element ref count match original ref count */
+
+ for (index = 0; index < (reference_count - 1);
+ index++) {
+ acpi_ut_add_reference((obj_desc->
+ package.
+ elements[i]));
+ }
+ }
+ }
+
arg = arg->common.next;
}
- if (!arg) {
+ /* Check for match between num_elements and actual length of package_list */
+
+ if (arg) {
+ /*
+ * num_elements was exhausted, but there are remaining elements in the
+ * package_list.
+ *
+ * Note: technically, this is an error, from ACPI spec: "It is an error
+ * for NumElements to be less than the number of elements in the
+ * PackageList". However, for now, we just print an error message and
+ * no exception is returned.
+ */
+ while (arg) {
+
+ /* Find out how many elements there really are */
+
+ i++;
+ arg = arg->common.next;
+ }
+
+ ACPI_ERROR((AE_INFO,
+ "Package List length (%X) larger than NumElements count (%X), truncated\n",
+ i, element_count));
+ } else if (i < element_count) {
+ /*
+ * Arg list (elements) was exhausted, but we did not reach num_elements count.
+ * Note: this is not an error, the package is padded out with NULLs.
+ */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Package List length larger than NumElements count (%X), truncated\n",
- element_count));
+ "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n",
+ i, element_count));
}
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
@@ -721,6 +774,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/* Node was saved in Op */
obj_desc->reference.node = op->common.node;
+ obj_desc->reference.object =
+ op->common.node->object;
}
obj_desc->reference.opcode = opcode;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index f501e083aac7..a818e0ddb996 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsopcode")
@@ -219,6 +220,50 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_get_bank_field_arguments
+ *
+ * PARAMETERS: obj_desc - A valid bank_field object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get bank_field bank_value. This implements the late
+ * evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object *extra_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the AML pointer (method object) and bank_field node */
+
+ extra_desc = acpi_ns_get_secondary_object(obj_desc);
+ node = obj_desc->bank_field.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
+ acpi_ut_get_node_name(node)));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ extra_desc->extra.aml_length,
+ extra_desc->extra.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_get_buffer_arguments
*
* PARAMETERS: obj_desc - A valid Buffer object
@@ -770,7 +815,109 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
obj_desc,
- ACPI_FORMAT_UINT64(obj_desc->region.address),
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
+ obj_desc->region.length));
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_table_region_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from acpi_ds_exec_end_op during data_table_region parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **operand;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ acpi_native_uint table_index;
+ struct acpi_table_header *table;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
+
+ /*
+ * This is where we evaluate the signature_string and oem_iDString
+ * and oem_table_iDString of the data_table_region declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to signature_string op */
+
+ next_op = op->common.value.arg;
+
+ /*
+ * Evaluate/create the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Resolve the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ex_resolve_operands(op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ 1, "after AcpiExResolveOperands");
+
+ operand = &walk_state->operands[0];
+
+ /* Find the ACPI table */
+
+ status = acpi_tb_find_table(operand[0]->string.pointer,
+ operand[1]->string.pointer,
+ operand[2]->string.pointer, &table_index);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ut_remove_reference(operand[0]);
+ acpi_ut_remove_reference(operand[1]);
+ acpi_ut_remove_reference(operand[2]);
+
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->region.address =
+ (acpi_physical_address) ACPI_TO_INTEGER(table);
+ obj_desc->region.length = table->length;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
+ obj_desc,
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
obj_desc->region.length));
/* Now the address and length are valid for this opregion */
@@ -808,6 +955,12 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
/* The first operand (for all of these data objects) is the length */
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ */
+ walk_state->operand_index = walk_state->num_operands;
+
status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -878,6 +1031,106 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_eval_bank_field_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid bank_field Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get bank_field bank_value
+ * Called from acpi_ds_exec_end_op during bank_field parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *operand_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ union acpi_parse_object *arg;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op);
+
+ /*
+ * This is where we evaluate the bank_value field of the
+ * bank_field declaration
+ */
+
+ /* next_op points to the op that holds the Region */
+
+ next_op = op->common.value.arg;
+
+ /* next_op points to the op that holds the Bank Register */
+
+ next_op = next_op->common.next;
+
+ /* next_op points to the op that holds the Bank Value */
+
+ next_op = next_op->common.next;
+
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ *
+ * We use walk_state->Operands[0] to store the evaluated bank_value
+ */
+ walk_state->operand_index = 0;
+
+ status = acpi_ds_create_operand(walk_state, next_op, 0);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ 1, "after AcpiExResolveOperands");
+
+ /*
+ * Get the bank_value operand and save it
+ * (at Top of stack)
+ */
+ operand_desc = walk_state->operands[0];
+
+ /* Arg points to the start Bank Field */
+
+ arg = acpi_ps_get_arg(op, 4);
+ while (arg) {
+
+ /* Ignore OFFSET and ACCESSAS terms here */
+
+ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+ node = arg->common.node;
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->bank_field.value =
+ (u32) operand_desc->integer.value;
+ }
+
+ /* Move to next field in the list */
+
+ arg = arg->common.next;
+ }
+
+ acpi_ut_remove_reference(operand_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_exec_begin_control_op
*
* PARAMETERS: walk_list - The list that owns the walk stack
@@ -1070,8 +1323,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
* is set to anything other than zero!
*/
walk_state->return_desc = walk_state->operands[0];
- } else if ((walk_state->results) &&
- (walk_state->results->results.num_results > 0)) {
+ } else if (walk_state->result_count) {
/* Since we have a real Return(), delete any implicit return */
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 71503c036f7c..b398982f0d8b 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -278,7 +278,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
AML_VAR_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
|| (op->common.parent->common.aml_opcode ==
- AML_INT_EVAL_SUBTREE_OP)) {
+ AML_INT_EVAL_SUBTREE_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)) {
/*
* These opcodes allow term_arg(s) as operands and therefore
* the operands can be method calls. The result is used.
@@ -472,7 +474,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
/* A valid name must be looked up in the namespace */
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
- (arg->common.value.string)) {
+ (arg->common.value.string) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
arg));
@@ -595,7 +598,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
} else {
/* Check for null name case */
- if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
/*
* If the name is null, this means that this is an
* optional result parameter that was not specified
@@ -617,7 +621,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
}
- if (op_info->flags & AML_HAS_RETVAL) {
+ if ((op_info->flags & AML_HAS_RETVAL)
+ || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Argument previously created, already stacked\n"));
@@ -630,9 +635,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
* Use value that was already previously returned
* by the evaluation of this argument
*/
- status =
- acpi_ds_result_pop_from_bottom(&obj_desc,
- walk_state);
+ status = acpi_ds_result_pop(&obj_desc, walk_state);
if (ACPI_FAILURE(status)) {
/*
* Only error is underflow, and this indicates
@@ -698,27 +701,52 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
{
acpi_status status = AE_OK;
union acpi_parse_object *arg;
+ union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
u32 arg_count = 0;
+ u32 index = walk_state->num_operands;
+ u32 i;
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
- /* For all arguments in the list... */
+ /* Get all arguments in the list */
arg = first_arg;
while (arg) {
- status = acpi_ds_create_operand(walk_state, arg, arg_count);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ if (index >= ACPI_OBJ_NUM_OPERANDS) {
+ return_ACPI_STATUS(AE_BAD_DATA);
}
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Arg #%d (%p) done, Arg1=%p\n", arg_count,
- arg, first_arg));
+ arguments[index] = arg;
+ walk_state->operands[index] = NULL;
/* Move on to next argument, if any */
arg = arg->common.next;
arg_count++;
+ index++;
+ }
+
+ index--;
+
+ /* It is the appropriate order to get objects from the Result stack */
+
+ for (i = 0; i < arg_count; i++) {
+ arg = arguments[index];
+
+ /* Force the filling of the operand stack in inverse order */
+
+ walk_state->operand_index = (u8) index;
+
+ status = acpi_ds_create_operand(walk_state, arg, index);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ index--;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Arg #%d (%p) done, Arg1=%p\n", index, arg,
+ first_arg));
}
return_ACPI_STATUS(status);
@@ -729,9 +757,112 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
* pop everything off of the operand stack and delete those
* objects
*/
- (void)acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+ acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+
+ ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_evaluate_name_path
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk,
+ * the opcode of current operation should be
+ * AML_INT_NAMEPATH_OP
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
+ * interpreter object, convert it to value, if needed, duplicate
+ * it, if needed, and push it onto the current result stack.
+ *
+ ****************************************************************************/
+
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = walk_state->op;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *new_obj_desc;
+ u8 type;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
+
+ if (!op->common.parent) {
+
+ /* This happens after certain exception processing */
+
+ goto exit;
+ }
+
+ if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
+
+ /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
+
+ goto exit;
+ }
+
+ status = acpi_ds_create_operand(walk_state, op, 0);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (op->common.flags & ACPI_PARSEOP_TARGET) {
+ new_obj_desc = *operand;
+ goto push_result;
+ }
+
+ type = ACPI_GET_OBJECT_TYPE(*operand);
+
+ status = acpi_ex_resolve_to_value(operand, walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (type == ACPI_TYPE_INTEGER) {
+
+ /* It was incremented by acpi_ex_resolve_to_value */
+
+ acpi_ut_remove_reference(*operand);
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+ } else {
+ /*
+ * The object either was anew created or is
+ * a Namespace node - don't decrement it.
+ */
+ new_obj_desc = *operand;
+ }
+
+ /* Cleanup for name-path operand */
+
+ status = acpi_ds_obj_stack_pop(1, walk_state);
+ if (ACPI_FAILURE(status)) {
+ walk_state->result_obj = new_obj_desc;
+ goto exit;
+ }
+
+ push_result:
+
+ walk_state->result_obj = new_obj_desc;
+
+ status = acpi_ds_result_push(walk_state->result_obj, walk_state);
+ if (ACPI_SUCCESS(status)) {
+
+ /* Force to take it from stack */
+
+ op->common.flags |= ACPI_PARSEOP_IN_STACK;
+ }
+
+ exit:
- ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d",
- (arg_count + 1)));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index 69693fa07224..b246b9657ead 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -285,11 +285,6 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
switch (opcode_class) {
case AML_CLASS_CONTROL:
- status = acpi_ds_result_stack_push(walk_state);
- if (ACPI_FAILURE(status)) {
- goto error_exit;
- }
-
status = acpi_ds_exec_begin_control_op(walk_state, op);
break;
@@ -305,20 +300,11 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_load2_begin_op(walk_state, NULL);
}
- if (op->common.aml_opcode == AML_REGION_OP) {
- status = acpi_ds_result_stack_push(walk_state);
- }
break;
case AML_CLASS_EXECUTE:
case AML_CLASS_CREATE:
- /*
- * Most operators with arguments (except create_xxx_field operators)
- * Start a new result/operand state
- */
- if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) {
- status = acpi_ds_result_stack_push(walk_state);
- }
+
break;
default:
@@ -374,6 +360,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
/* Init the walk state */
walk_state->num_operands = 0;
+ walk_state->operand_index = 0;
walk_state->return_desc = NULL;
walk_state->result_obj = NULL;
@@ -388,10 +375,17 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
/* Decode the Opcode Class */
switch (op_class) {
- case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */
+ case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */
+
+ if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+ status = acpi_ds_evaluate_name_path(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
break;
- case AML_CLASS_EXECUTE: /* most operators with arguments */
+ case AML_CLASS_EXECUTE: /* Most operators with arguments */
/* Build resolved operand stack */
@@ -400,13 +394,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
goto cleanup;
}
- /* Done with this result state (Now that operand stack is built) */
-
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
/*
* All opcodes require operand resolution, with the only exceptions
* being the object_type and size_of operators.
@@ -487,16 +474,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
status = acpi_ds_exec_end_control_op(walk_state, op);
- /* Make sure to properly pop the result stack */
-
- if (ACPI_SUCCESS(status)) {
- status = acpi_ds_result_stack_pop(walk_state);
- } else if (status == AE_CTRL_PENDING) {
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_PENDING;
- }
- }
break;
case AML_TYPE_METHOD_CALL:
@@ -516,7 +493,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
op->common.node =
(struct acpi_namespace_node *)op->asl.value.
- arg->asl.node->object;
+ arg->asl.node;
acpi_ut_add_reference(op->asl.value.arg->asl.
node->object);
return_ACPI_STATUS(AE_OK);
@@ -632,13 +609,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
break;
}
- /* Done with result state (Now that operand stack is built) */
-
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
/*
* If a result object was returned from above, push it on the
* current result stack
@@ -671,8 +641,28 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
break;
}
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing DataTableRegion Strings Op=%p\n",
+ op));
+
+ status =
+ acpi_ds_eval_table_region_operands
+ (walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ } else if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing BankField Op=%p\n",
+ op));
- status = acpi_ds_result_stack_pop(walk_state);
+ status =
+ acpi_ds_eval_bank_field_operands(walk_state,
+ op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
}
break;
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 8ab9d1b29a4c..dff7a3e445a8 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -443,6 +443,15 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ status =
+ acpi_ex_create_region(op->named.data,
+ op->named.length,
+ REGION_DATA_TABLE,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
#endif
@@ -767,6 +776,12 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
object_type, ACPI_IMODE_LOAD_PASS2, flags,
walk_state, &node);
+
+ if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "***New Node [%4.4s] %p is temporary\n",
+ acpi_ut_get_node_name(node), node));
+ }
break;
}
@@ -823,6 +838,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
struct acpi_namespace_node *new_node;
#ifndef ACPI_NO_METHOD_EXECUTION
u32 i;
+ u8 region_space;
#endif
ACPI_FUNCTION_TRACE(ds_load2_end_op);
@@ -1003,11 +1019,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
status = acpi_ex_create_event(walk_state);
break;
- case AML_DATA_REGION_OP:
-
- status = acpi_ex_create_table_region(walk_state);
- break;
-
case AML_ALIAS_OP:
status = acpi_ex_create_alias(walk_state);
@@ -1035,6 +1046,15 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
switch (op->common.aml_opcode) {
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_REGION_OP:
+ case AML_DATA_REGION_OP:
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ region_space = (acpi_adr_space_type)
+ ((op->common.value.arg)->common.value.
+ integer);
+ } else {
+ region_space = REGION_DATA_TABLE;
+ }
/*
* If we are executing a method, initialize the region
@@ -1043,10 +1063,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
status =
acpi_ex_create_region(op->named.data,
op->named.length,
- (acpi_adr_space_type)
- ((op->common.value.
- arg)->common.value.
- integer),
+ region_space,
walk_state);
if (ACPI_FAILURE(status)) {
return (status);
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index 3927c495e4bf..9e6073265873 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 5afcdd9c7449..1386ced332ec 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,85 +49,9 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswstate")
-/* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_ds_result_insert(void *object,
- u32 index, struct acpi_walk_state *walk_state);
-
-acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state *walk_state);
-
-acpi_status
-acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state);
-
-void *acpi_ds_obj_stack_get_value(u32 index,
- struct acpi_walk_state *walk_state);
-#endif
-
-#ifdef ACPI_FUTURE_USAGE
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_remove
- *
- * PARAMETERS: Object - Where to return the popped object
- * Index - Where to extract the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_remove(union acpi_operand_object **object,
- u32 index, struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_remove);
-
- state = walk_state->results;
- if (!state) {
- ACPI_ERROR((AE_INFO, "No result object pushed! State=%p",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_MAX_OPERAND) {
- ACPI_ERROR((AE_INFO,
- "Index out of range: %X State=%p Num=%X",
- index, walk_state, state->results.num_results));
- }
-
- /* Check for a valid result object */
-
- if (!state->results.obj_desc[index]) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X, Index=%X",
- walk_state, state->results.num_results, index));
- return (AE_AML_NO_RETURN_VALUE);
- }
-
- /* Remove the object */
-
- state->results.num_results--;
-
- *object = state->results.obj_desc[index];
- state->results.obj_desc[index] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object,
- (*object) ? acpi_ut_get_object_type_name(*object) :
- "NULL", index, walk_state,
- state->results.num_results));
-
- return (AE_OK);
-}
-#endif /* ACPI_FUTURE_USAGE */
+ /* Local prototypes */
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws);
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws);
/*******************************************************************************
*
@@ -138,122 +62,67 @@ acpi_ds_result_remove(union acpi_operand_object **object,
*
* RETURN: Status
*
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
+ * DESCRIPTION: Pop an object off the top of this walk's result stack
*
******************************************************************************/
acpi_status
-acpi_ds_result_pop(union acpi_operand_object ** object,
- struct acpi_walk_state * walk_state)
+acpi_ds_result_pop(union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
{
acpi_native_uint index;
union acpi_generic_state *state;
+ acpi_status status;
ACPI_FUNCTION_NAME(ds_result_pop);
state = walk_state->results;
- if (!state) {
- return (AE_OK);
- }
-
- if (!state->results.num_results) {
- ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
- walk_state));
- return (AE_AML_NO_RETURN_VALUE);
- }
- /* Remove top element */
+ /* Incorrect state of result stack */
- state->results.num_results--;
-
- for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) {
-
- /* Check for a valid result object */
-
- if (state->results.obj_desc[index - 1]) {
- *object = state->results.obj_desc[index - 1];
- state->results.obj_desc[index - 1] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object,
- (*object) ?
- acpi_ut_get_object_type_name(*object)
- : "NULL", (u32) index - 1, walk_state,
- state->results.num_results));
-
- return (AE_OK);
- }
+ if (state && !walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No results on result stack"));
+ return (AE_AML_INTERNAL);
}
- ACPI_ERROR((AE_INFO, "No result objects! State=%p", walk_state));
- return (AE_AML_NO_RETURN_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_pop_from_bottom
- *
- * PARAMETERS: Object - Where to return the popped object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_pop_from_bottom(union acpi_operand_object ** object,
- struct acpi_walk_state * walk_state)
-{
- acpi_native_uint index;
- union acpi_generic_state *state;
+ if (!state && walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No result state for result stack"));
+ return (AE_AML_INTERNAL);
+ }
- ACPI_FUNCTION_NAME(ds_result_pop_from_bottom);
+ /* Empty result stack */
- state = walk_state->results;
if (!state) {
- ACPI_ERROR((AE_INFO,
- "No result object pushed! State=%p", walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (!state->results.num_results) {
- ACPI_ERROR((AE_INFO, "No result objects! State=%p",
+ ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
- /* Remove Bottom element */
-
- *object = state->results.obj_desc[0];
-
- /* Push entire stack down one element */
-
- for (index = 0; index < state->results.num_results; index++) {
- state->results.obj_desc[index] =
- state->results.obj_desc[index + 1];
- }
+ /* Return object of the top element and clean that top element result stack */
- state->results.num_results--;
-
- /* Check for a valid result object */
+ walk_state->result_count--;
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+ *object = state->results.obj_desc[index];
if (!*object) {
ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X Index=%X",
- walk_state, state->results.num_results,
- (u32) index));
+ "No result objects on result stack, State=%p",
+ walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] Results=%p State=%p\n",
- *object,
- (*object) ? acpi_ut_get_object_type_name(*object) :
- "NULL", state, walk_state));
+ state->results.obj_desc[index] = NULL;
+ if (index == 0) {
+ status = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
+ acpi_ut_get_object_type_name(*object),
+ (u32) index, walk_state, walk_state->result_count));
return (AE_OK);
}
@@ -276,39 +145,56 @@ acpi_ds_result_push(union acpi_operand_object * object,
struct acpi_walk_state * walk_state)
{
union acpi_generic_state *state;
+ acpi_status status;
+ acpi_native_uint index;
ACPI_FUNCTION_NAME(ds_result_push);
+ if (walk_state->result_count > walk_state->result_size) {
+ ACPI_ERROR((AE_INFO, "Result stack is full"));
+ return (AE_AML_INTERNAL);
+ } else if (walk_state->result_count == walk_state->result_size) {
+
+ /* Extend the result stack */
+
+ status = acpi_ds_result_stack_push(walk_state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Failed to extend the result stack"));
+ return (status);
+ }
+ }
+
+ if (!(walk_state->result_count < walk_state->result_size)) {
+ ACPI_ERROR((AE_INFO, "No free elements in result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
state = walk_state->results;
if (!state) {
ACPI_ERROR((AE_INFO, "No result stack frame during push"));
return (AE_AML_INTERNAL);
}
- if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) {
- ACPI_ERROR((AE_INFO,
- "Result stack overflow: Obj=%p State=%p Num=%X",
- object, walk_state, state->results.num_results));
- return (AE_STACK_OVERFLOW);
- }
-
if (!object) {
ACPI_ERROR((AE_INFO,
"Null Object! Obj=%p State=%p Num=%X",
- object, walk_state, state->results.num_results));
+ object, walk_state, walk_state->result_count));
return (AE_BAD_PARAMETER);
}
- state->results.obj_desc[state->results.num_results] = object;
- state->results.num_results++;
+ /* Assign the address of object to the top free element of result stack */
+
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+ state->results.obj_desc[index] = object;
+ walk_state->result_count++;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
object,
- object ?
acpi_ut_get_object_type_name((union
acpi_operand_object *)
- object) : "NULL",
- walk_state, state->results.num_results,
+ object), walk_state,
+ walk_state->result_count,
walk_state->current_result));
return (AE_OK);
@@ -322,16 +208,25 @@ acpi_ds_result_push(union acpi_operand_object * object,
*
* RETURN: Status
*
- * DESCRIPTION: Push an object onto the walk_state result stack.
+ * DESCRIPTION: Push an object onto the walk_state result stack
*
******************************************************************************/
-acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
ACPI_FUNCTION_NAME(ds_result_stack_push);
+ /* Check for stack overflow */
+
+ if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) >
+ ACPI_RESULTS_OBJ_NUM_MAX) {
+ ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%X",
+ walk_state, walk_state->result_size));
+ return (AE_STACK_OVERFLOW);
+ }
+
state = acpi_ut_create_generic_state();
if (!state) {
return (AE_NO_MEMORY);
@@ -340,6 +235,10 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
acpi_ut_push_generic_state(&walk_state->results, state);
+ /* Increase the length of the result stack by the length of frame */
+
+ walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM;
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
state, walk_state));
@@ -354,11 +253,11 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
*
* RETURN: Status
*
- * DESCRIPTION: Pop an object off of the walk_state result stack.
+ * DESCRIPTION: Pop an object off of the walk_state result stack
*
******************************************************************************/
-acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
@@ -367,18 +266,27 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
/* Check for stack underflow */
if (walk_state->results == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Underflow - State=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Result stack underflow - State=%p\n",
walk_state));
return (AE_AML_NO_OPERAND);
}
+ if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) {
+ ACPI_ERROR((AE_INFO, "Insufficient result stack size"));
+ return (AE_AML_INTERNAL);
+ }
+
state = acpi_ut_pop_generic_state(&walk_state->results);
+ acpi_ut_delete_generic_state(state);
+
+ /* Decrease the length of result stack by the length of frame */
+
+ walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Result=%p RemainingResults=%X State=%p\n",
- state, state->results.num_results, walk_state));
-
- acpi_ut_delete_generic_state(state);
+ state, walk_state->result_count, walk_state));
return (AE_OK);
}
@@ -412,9 +320,13 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state)
/* Put the object onto the stack */
- walk_state->operands[walk_state->num_operands] = object;
+ walk_state->operands[walk_state->operand_index] = object;
walk_state->num_operands++;
+ /* For the usual order of filling the operand stack */
+
+ walk_state->operand_index++;
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
object,
acpi_ut_get_object_type_name((union
@@ -484,43 +396,36 @@ acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state)
*
******************************************************************************/
-acpi_status
+void
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
- struct acpi_walk_state * walk_state)
+ struct acpi_walk_state *walk_state)
{
- u32 i;
+ acpi_native_int i;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
- for (i = 0; i < pop_count; i++) {
-
- /* Check for stack underflow */
+ if (pop_count == 0) {
+ return;
+ }
+ for (i = (acpi_native_int) (pop_count - 1); i >= 0; i--) {
if (walk_state->num_operands == 0) {
- ACPI_ERROR((AE_INFO,
- "Object stack underflow! Count=%X State=%p #Ops=%X",
- pop_count, walk_state,
- walk_state->num_operands));
- return (AE_STACK_UNDERFLOW);
+ return;
}
/* Pop the stack and delete an object if present in this stack entry */
walk_state->num_operands--;
- obj_desc = walk_state->operands[walk_state->num_operands];
+ obj_desc = walk_state->operands[i];
if (obj_desc) {
- acpi_ut_remove_reference(walk_state->
- operands[walk_state->
- num_operands]);
- walk_state->operands[walk_state->num_operands] = NULL;
+ acpi_ut_remove_reference(walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
}
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
pop_count, walk_state, walk_state->num_operands));
-
- return (AE_OK);
}
/*******************************************************************************
@@ -560,7 +465,7 @@ struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
*
* RETURN: None
*
- * DESCRIPTION: Place the Thread state at the head of the state list.
+ * DESCRIPTION: Place the Thread state at the head of the state list
*
******************************************************************************/
@@ -636,7 +541,6 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union
*thread)
{
struct acpi_walk_state *walk_state;
- acpi_status status;
ACPI_FUNCTION_TRACE(ds_create_walk_state);
@@ -659,14 +563,6 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union
acpi_ds_method_data_init(walk_state);
#endif
- /* Create an initial result stack entry */
-
- status = acpi_ds_result_stack_push(walk_state);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(walk_state);
- return_PTR(NULL);
- }
-
/* Put the new state at the head of the walk list */
if (thread) {
@@ -860,190 +756,3 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
ACPI_FREE(walk_state);
return_VOID;
}
-
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_insert
- *
- * PARAMETERS: Object - Object to push
- * Index - Where to insert the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Insert an object onto this walk's result stack
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_insert(void *object,
- u32 index, struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_insert);
-
- state = walk_state->results;
- if (!state) {
- ACPI_ERROR((AE_INFO, "No result object pushed! State=%p",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_NUM_OPERANDS) {
- ACPI_ERROR((AE_INFO,
- "Index out of range: %X Obj=%p State=%p Num=%X",
- index, object, walk_state,
- state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- if (!object) {
- ACPI_ERROR((AE_INFO,
- "Null Object! Index=%X Obj=%p State=%p Num=%X",
- index, object, walk_state,
- state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- state->results.obj_desc[index] = object;
- state->results.num_results++;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
- object,
- object ?
- acpi_ut_get_object_type_name((union
- acpi_operand_object *)
- object) : "NULL",
- walk_state, state->results.num_results,
- walk_state->current_result));
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_delete_all
- *
- * PARAMETERS: walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
- * Should be used with great care, if at all!
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state * walk_state)
-{
- u32 i;
-
- ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_delete_all, walk_state);
-
- /* The stack size is configurable, but fixed */
-
- for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) {
- if (walk_state->operands[i]) {
- acpi_ut_remove_reference(walk_state->operands[i]);
- walk_state->operands[i] = NULL;
- }
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_pop_object
- *
- * PARAMETERS: Object - Where to return the popped object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
- * deleted by this routine.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state)
-{
- ACPI_FUNCTION_NAME(ds_obj_stack_pop_object);
-
- /* Check for stack underflow */
-
- if (walk_state->num_operands == 0) {
- ACPI_ERROR((AE_INFO,
- "Missing operand/stack empty! State=%p #Ops=%X",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Pop the stack */
-
- walk_state->num_operands--;
-
- /* Check for a valid operand */
-
- if (!walk_state->operands[walk_state->num_operands]) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Get operand and set stack entry to null */
-
- *object = walk_state->operands[walk_state->num_operands];
- walk_state->operands[walk_state->num_operands] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
- *object, acpi_ut_get_object_type_name(*object),
- walk_state, walk_state->num_operands));
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_get_value
- *
- * PARAMETERS: Index - Stack index whose value is desired. Based
- * on the top of the stack (index=0 == top)
- * walk_state - Current Walk state
- *
- * RETURN: Pointer to the requested operand
- *
- * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must
- * be within the range of the current stack pointer.
- *
- ******************************************************************************/
-
-void *acpi_ds_obj_stack_get_value(u32 index, struct acpi_walk_state *walk_state)
-{
-
- ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_get_value, walk_state);
-
- /* Can't do it if the stack is empty */
-
- if (walk_state->num_operands == 0) {
- return_PTR(NULL);
- }
-
- /* or if the index is past the top of the stack */
-
- if (index > (walk_state->num_operands - (u32) 1)) {
- return_PTR(NULL);
- }
-
- return_PTR(walk_state->
- operands[(acpi_native_uint) (walk_state->num_operands - 1) -
- index]);
-}
-#endif
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7222a18a0319..0924992187e8 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -73,38 +73,14 @@ enum ec_event {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
- EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
- EC_FLAGS_ADDRESS, /* Address is being written */
- EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
- EC_FLAGS_WDATA, /* Data is being written */
- EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
-};
-
-static int acpi_ec_remove(struct acpi_device *device, int type);
-static int acpi_ec_start(struct acpi_device *device);
-static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_add(struct acpi_device *device);
-
-static const struct acpi_device_id ec_device_ids[] = {
- {"PNP0C09", 0},
- {"", 0},
-};
-
-static struct acpi_driver acpi_ec_driver = {
- .name = "ec",
- .class = ACPI_EC_CLASS,
- .ids = ec_device_ids,
- .ops = {
- .add = acpi_ec_add,
- .remove = acpi_ec_remove,
- .start = acpi_ec_start,
- .stop = acpi_ec_stop,
- },
+ EC_FLAGS_NO_GPE, /* Don't use GPE mode */
+ EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -129,6 +105,8 @@ static struct acpi_ec {
struct mutex lock;
wait_queue_head_t wait;
struct list_head list;
+ struct delayed_work work;
+ atomic_t irq_count;
u8 handlers_installed;
} *boot_ec, *first_ec;
@@ -177,65 +155,52 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
return 0;
}
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
+static void ec_schedule_ec_poll(struct acpi_ec *ec)
{
- int ret = 0;
+ if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
+ schedule_delayed_work(&ec->work,
+ msecs_to_jiffies(ACPI_EC_DELAY));
+}
+
+static void ec_switch_to_poll_mode(struct acpi_ec *ec)
+{
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+}
- if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
- test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
- test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
- test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
- force_poll = 1;
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
+{
+ atomic_set(&ec->irq_count, 0);
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
msecs_to_jiffies(ACPI_EC_DELAY)))
- goto end;
+ return 0;
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (acpi_ec_check_status(ec, event)) {
- if (event == ACPI_EC_EVENT_OBF_1) {
- /* miss OBF_1 GPE, don't expect it */
- pr_info(PREFIX "missing OBF confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
- /* miss address GPE, don't expect it anymore */
- pr_info(PREFIX "missing address confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
- /* miss write data GPE, don't expect it */
- pr_info(PREFIX "missing write data confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
- } else {
- /* missing GPEs, switch back to poll mode */
- if (printk_ratelimit())
- pr_info(PREFIX "missing confirmations, "
+ /* missing GPEs, switch back to poll mode */
+ if (printk_ratelimit())
+ pr_info(PREFIX "missing confirmations, "
"switch off interrupt mode.\n");
- clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- }
- goto end;
+ ec_switch_to_poll_mode(ec);
+ ec_schedule_ec_poll(ec);
+ return 0;
}
} else {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
- goto end;
+ return 0;
+ udelay(ACPI_EC_UDELAY);
}
}
- pr_err(PREFIX "acpi_ec_wait timeout,"
- " status = %d, expect_event = %d\n",
- acpi_ec_read_status(ec), event);
- ret = -ETIME;
- end:
- clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
- return ret;
+ pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
+ acpi_ec_read_status(ec),
+ (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
+ return -ETIME;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -245,8 +210,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
{
int result = 0;
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- acpi_ec_write_cmd(ec, command);
pr_debug(PREFIX "transaction start\n");
+ acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
@@ -254,15 +219,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
"write_cmd timeout, command = %d\n", command);
goto end;
}
- /* mark the address byte written to EC */
- if (rdata_len + wdata_len > 1)
- set_bit(EC_FLAGS_ADDRESS, &ec->flags);
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
- set_bit(EC_FLAGS_WDATA, &ec->flags);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
pr_err(PREFIX
@@ -527,47 +488,51 @@ static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status status = AE_OK;
struct acpi_ec *ec = data;
+ u8 state = acpi_ec_read_status(ec);
pr_debug(PREFIX "~~~> interrupt\n");
+ atomic_inc(&ec->irq_count);
+ if (atomic_read(&ec->irq_count) > 5) {
+ pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+ ec_switch_to_poll_mode(ec);
+ goto end;
+ }
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {
+ if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
status = acpi_os_execute(OSL_EC_BURST_HANDLER,
acpi_ec_gpe_query, ec);
- } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
+ } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+ !test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
+ in_interrupt()) {
/* this is non-query, must be confirmation */
if (printk_ratelimit())
pr_info(PREFIX "non-query interrupt received,"
" switching to interrupt mode\n");
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
}
-
+end:
+ ec_schedule_ec_poll(ec);
return ACPI_SUCCESS(status) ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
+static void do_ec_poll(struct work_struct *work)
+{
+ struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
+ atomic_set(&ec->irq_count, 0);
+ (void)acpi_ec_gpe_handler(ec);
+}
+
/* --------------------------------------------------------------------------
Address Space Management
-------------------------------------------------------------------------- */
static acpi_status
-acpi_ec_space_setup(acpi_handle region_handle,
- u32 function, void *handler_context, void **return_context)
-{
- /*
- * The EC object is in the handler context and is needed
- * when calling the acpi_ec_space_handler.
- */
- *return_context = (function != ACPI_REGION_DEACTIVATE) ?
- handler_context : NULL;
-
- return AE_OK;
-}
-
-static acpi_status
acpi_ec_space_handler(u32 function, acpi_physical_address address,
u32 bits, acpi_integer *value,
void *handler_context, void *region_context)
@@ -669,16 +634,11 @@ static int acpi_ec_add_fs(struct acpi_device *device)
return -ENODEV;
}
- entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO,
+ acpi_device_dir(device),
+ &acpi_ec_info_ops, acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_ec_info_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
@@ -709,6 +669,8 @@ static struct acpi_ec *make_acpi_ec(void)
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
+ INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
+ atomic_set(&ec->irq_count, 0);
return ec;
}
@@ -741,17 +703,21 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status))
return status;
- /* Find and register all query methods */
- acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
- acpi_ec_register_query_methods, ec, NULL);
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
ec->handle = handle;
return AE_CTRL_TERMINATE;
}
+static void ec_poll_stop(struct acpi_ec *ec)
+{
+ clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+ cancel_delayed_work(&ec->work);
+}
+
static void ec_remove_handlers(struct acpi_ec *ec)
{
+ ec_poll_stop(ec);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n");
@@ -771,31 +737,28 @@ static int acpi_ec_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
/* Check for boot EC */
- if (boot_ec) {
- if (boot_ec->handle == device->handle) {
- /* Pre-loaded EC from DSDT, just move pointer */
- ec = boot_ec;
- boot_ec = NULL;
- goto end;
- } else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
- /* ECDT-based EC, time to shut it down */
- ec_remove_handlers(boot_ec);
- kfree(boot_ec);
- first_ec = boot_ec = NULL;
+ if (boot_ec &&
+ (boot_ec->handle == device->handle ||
+ boot_ec->handle == ACPI_ROOT_OBJECT)) {
+ ec = boot_ec;
+ boot_ec = NULL;
+ } else {
+ ec = make_acpi_ec();
+ if (!ec)
+ return -ENOMEM;
+ if (ec_parse_device(device->handle, 0, ec, NULL) !=
+ AE_CTRL_TERMINATE) {
+ kfree(ec);
+ return -EINVAL;
}
}
- ec = make_acpi_ec();
- if (!ec)
- return -ENOMEM;
-
- if (ec_parse_device(device->handle, 0, ec, NULL) !=
- AE_CTRL_TERMINATE) {
- kfree(ec);
- return -EINVAL;
- }
ec->handle = device->handle;
- end:
+
+ /* Find and register all query methods */
+ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
+ acpi_ec_register_query_methods, ec, NULL);
+
if (!first_ec)
first_ec = ec;
acpi_driver_data(device) = ec;
@@ -870,7 +833,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
- &acpi_ec_space_setup, ec);
+ NULL, ec);
if (ACPI_FAILURE(status)) {
acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
return -ENODEV;
@@ -897,6 +860,7 @@ static int acpi_ec_start(struct acpi_device *device)
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ ec_schedule_ec_poll(ec);
return ret;
}
@@ -924,6 +888,11 @@ int __init acpi_boot_ec_enable(void)
return -EFAULT;
}
+static const struct acpi_device_id ec_device_ids[] = {
+ {"PNP0C09", 0},
+ {"", 0},
+};
+
int __init acpi_ec_ecdt_probe(void)
{
int ret;
@@ -944,6 +913,7 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
+ acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
} else {
/* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */
@@ -973,6 +943,39 @@ int __init acpi_ec_ecdt_probe(void)
return -ENODEV;
}
+static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Stop using GPE */
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static int acpi_ec_resume(struct acpi_device *device)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Enable use of GPE back */
+ clear_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static struct acpi_driver acpi_ec_driver = {
+ .name = "ec",
+ .class = ACPI_EC_CLASS,
+ .ids = ec_device_ids,
+ .ops = {
+ .add = acpi_ec_add,
+ .remove = acpi_ec_remove,
+ .start = acpi_ec_start,
+ .stop = acpi_ec_stop,
+ .suspend = acpi_ec_suspend,
+ .resume = acpi_ec_resume,
+ },
+};
+
static int __init acpi_ec_init(void)
{
int result = 0;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index abec1ca94cf4..0c24bd4d6562 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -102,6 +102,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
}
static const struct file_operations acpi_system_event_ops = {
+ .owner = THIS_MODULE,
.open = acpi_system_open_event,
.read = acpi_system_read_event,
.release = acpi_system_close_event,
@@ -294,10 +295,9 @@ static int __init acpi_event_init(void)
#ifdef CONFIG_ACPI_PROC_EVENT
/* 'event' [R] */
- entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_event_ops;
- else
+ entry = proc_create("event", S_IRUSR, acpi_root_dir,
+ &acpi_system_event_ops);
+ if (!entry)
return -ENODEV;
#endif
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 3048801a37b5..5d30e5be1b1c 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 0dadd2adc800..5354be44f876 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -248,10 +248,6 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
ACPI_FUNCTION_TRACE(ev_disable_gpe);
- if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) {
- return_ACPI_STATUS(AE_OK);
- }
-
/* Make sure HW enable masks are updated */
status =
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 361ebe6c4a6f..e6c4d4c49e79 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 21cb749d0c75..2113e58e2221 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,22 +49,7 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evmisc")
-/* Names for Notify() values, used for debug output */
-#ifdef ACPI_DEBUG_OUTPUT
-static const char *acpi_notify_value_names[] = {
- "Bus Check",
- "Device Check",
- "Device Wake",
- "Eject Request",
- "Device Check Light",
- "Frequency Mismatch",
- "Bus Mode Mismatch",
- "Power Fault"
-};
-#endif
-
/* Pointer to FACS needed for the Global Lock */
-
static struct acpi_table_facs *facs = NULL;
/* Local prototypes */
@@ -94,7 +79,6 @@ u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
switch (node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL:
/*
* These are the ONLY objects that can receive ACPI notifications
@@ -139,17 +123,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
* initiate soft-off or sleep operation?
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Dispatching Notify(%X) on node %p\n", notify_value,
- node));
-
- if (notify_value <= 7) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n",
- acpi_notify_value_names[notify_value]));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Notify value: 0x%2.2X **Device Specific**\n",
- notify_value));
- }
+ "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
+ acpi_ut_get_node_name(node), node, notify_value,
+ acpi_ut_get_notify_name(notify_value)));
/* Get the notify object attached to the NS Node */
@@ -159,10 +135,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
/* We have the notify object, Get the right handler */
switch (node->type) {
+
+ /* Notify allowed only on these types */
+
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_POWER:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj =
@@ -179,8 +157,13 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
}
}
- /* If there is any handler to run, schedule the dispatcher */
-
+ /*
+ * If there is any handler to run, schedule the dispatcher.
+ * Check for:
+ * 1) Global system notify handler
+ * 2) Global device notify handler
+ * 3) Per-device notify handler
+ */
if ((acpi_gbl_system_notify.handler
&& (notify_value <= ACPI_MAX_SYS_NOTIFY))
|| (acpi_gbl_device_notify.handler
@@ -190,6 +173,13 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
return (AE_NO_MEMORY);
}
+ if (!handler_obj) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Executing system notify handler for Notify (%4.4s, %X) node %p\n",
+ acpi_ut_get_node_name(node),
+ notify_value, node));
+ }
+
notify_info->common.descriptor_type =
ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
@@ -202,15 +192,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
}
- }
-
- if (!handler_obj) {
+ } else {
/*
- * There is no per-device notify handler for this device.
- * This may or may not be a problem.
+ * There is no notify handler (per-device or system) for this device.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "No notify handler for Notify(%4.4s, %X) node %p\n",
+ "No notify handler for Notify (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));
}
@@ -349,9 +336,10 @@ 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);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -439,7 +427,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
* 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, 0);
+ status = acpi_ex_system_wait_mutex(
+ acpi_gbl_global_lock_mutex->mutex.os_mutex, 0);
if (status == AE_TIME) {
if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) {
acpi_ev_global_lock_acquired++;
@@ -448,9 +437,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
}
if (ACPI_FAILURE(status)) {
- status =
- acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex,
- timeout);
+ status = acpi_ex_system_wait_mutex(
+ acpi_gbl_global_lock_mutex->mutex.os_mutex,
+ timeout);
}
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -460,6 +449,19 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
acpi_ev_global_lock_acquired++;
/*
+ * Update the global lock handle and check for wraparound. The handle is
+ * only used for the external global lock interfaces, but it is updated
+ * here to properly handle the case where a single thread may acquire the
+ * lock via both the AML and the acpi_acquire_global_lock interfaces. The
+ * handle is therefore updated on the first acquire from a given thread
+ * regardless of where the acquisition request originated.
+ */
+ acpi_gbl_global_lock_handle++;
+ if (acpi_gbl_global_lock_handle == 0) {
+ acpi_gbl_global_lock_handle = 1;
+ }
+
+ /*
* Make sure that a global lock actually exists. If not, just treat
* the lock as a standard mutex.
*/
@@ -555,7 +557,7 @@ acpi_status acpi_ev_release_global_lock(void)
/* Release the local GL mutex */
acpi_ev_global_lock_thread_id = NULL;
acpi_ev_global_lock_acquired = 0;
- acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 58ad09725dd2..1628f5934752 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -394,7 +394,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.handler->address_space, handler,
- ACPI_FORMAT_UINT64(address),
+ ACPI_FORMAT_NATIVE_UINT(address),
acpi_ut_get_region_name(region_obj->region.
space_id)));
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index b1aaa0e84588..2e3d2c5e4f4d 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 7e5d15ce2395..2a8b77877610 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 6d866a01f5f4..94a6efe020be 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -758,6 +758,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
*
* DESCRIPTION: Acquire the ACPI Global Lock
*
+ * Note: Allows callers with the same thread ID to acquire the global lock
+ * multiple times. In other words, externally, the behavior of the global lock
+ * is identical to an AML mutex. On the first acquire, a new handle is
+ * returned. On any subsequent calls to acquire by the same thread, the same
+ * handle is returned.
+ *
******************************************************************************/
acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
{
@@ -770,14 +776,19 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
/* Must lock interpreter to prevent race conditions */
acpi_ex_enter_interpreter();
- status = acpi_ev_acquire_global_lock(timeout);
- acpi_ex_exit_interpreter();
+
+ status = acpi_ex_acquire_mutex_object(timeout,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
if (ACPI_SUCCESS(status)) {
- acpi_gbl_global_lock_handle++;
+
+ /* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */
+
*handle = acpi_gbl_global_lock_handle;
}
+ acpi_ex_exit_interpreter();
return (status);
}
@@ -798,11 +809,11 @@ acpi_status acpi_release_global_lock(u32 handle)
{
acpi_status status;
- if (handle != acpi_gbl_global_lock_handle) {
+ if (!handle || (handle != acpi_gbl_global_lock_handle)) {
return (AE_NOT_ACQUIRED);
}
- status = acpi_ev_release_global_lock();
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
return (status);
}
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 9cbd3414a574..99a7502e6a87 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 7bf09c5fb242..e8750807e57d 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 25802f302ffe..24da921d13e3 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
#include <acpi/actables.h>
#include <acpi/acdispat.h>
@@ -138,6 +137,14 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE(ex_load_table_op);
+ /* Validate lengths for the signature_string, OEMIDString, OEMtable_iD */
+
+ if ((operand[0]->string.length > ACPI_NAME_SIZE) ||
+ (operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
+ (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
/* Find the ACPI table in the RSDT/XSDT */
status = acpi_tb_find_table(operand[0]->string.pointer,
@@ -229,11 +236,18 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
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]",
+ "Dynamic OEM Table Load - [%.4s] OemId [%.6s] OemTableId [%.8s]",
table->signature, table->oem_id,
table->oem_table_id));
}
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
+ acpi_gbl_table_handler_context);
+ }
+
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
}
@@ -268,6 +282,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
struct acpi_table_desc table_desc;
acpi_native_uint table_index;
acpi_status status;
+ u32 length;
ACPI_FUNCTION_TRACE(ex_load_op);
@@ -278,16 +293,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
+ obj_desc,
+ acpi_ut_get_object_type_name(obj_desc)));
+
/* 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)));
-
/*
* If the Region Address and Length have not been previously evaluated,
* evaluate them now and save the results.
@@ -299,6 +314,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
}
+ /*
+ * We will simply map the memory region for the table. However, the
+ * memory region is technically not guaranteed to remain stable and
+ * we may eventually have to copy the table to a local buffer.
+ */
table_desc.address = obj_desc->region.address;
table_desc.length = obj_desc->region.length;
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
@@ -306,18 +326,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
- /* Simply extract the buffer from the buffer object */
-
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Load from Buffer or Field %p %s\n", obj_desc,
acpi_ut_get_object_type_name(obj_desc)));
- 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;
+ length = obj_desc->buffer.length;
+
+ /* Must have at least an ACPI table header */
+
+ if (length < sizeof(struct acpi_table_header)) {
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
+
+ /* Validate checksum here. It won't get validated in tb_add_table */
- obj_desc->buffer.pointer = NULL;
+ status =
+ acpi_tb_verify_checksum(ACPI_CAST_PTR
+ (struct acpi_table_header,
+ obj_desc->buffer.pointer), length);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * We need to copy the buffer since the original buffer could be
+ * changed or deleted in the future
+ */
+ table_desc.pointer = ACPI_ALLOCATE(length);
+ if (!table_desc.pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer,
+ length);
+ table_desc.length = length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
break;
default:
@@ -333,7 +376,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
status =
- acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
+ acpi_ex_add_table(table_index, walk_state->scope_info->scope.node,
+ &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
@@ -349,11 +393,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* table_ptr was deallocated above */
+ acpi_ut_remove_reference(ddb_handle);
return_ACPI_STATUS(status);
}
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD,
+ table_desc.pointer,
+ acpi_gbl_table_handler_context);
+ }
+
cleanup:
if (ACPI_FAILURE(status)) {
+
+ /* Delete allocated buffer or mapping */
+
acpi_tb_delete_table(&table_desc);
}
return_ACPI_STATUS(status);
@@ -376,6 +432,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;
acpi_native_uint table_index;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -395,17 +452,25 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
table_index = (acpi_native_uint) table_desc->reference.object;
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_SUCCESS(status)) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD,
+ table,
+ acpi_gbl_table_handler_context);
+ }
+ }
+
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
acpi_tb_delete_namespace_by_owner(table_index);
- acpi_tb_release_owner_id(table_index);
+ (void)acpi_tb_release_owner_id(table_index);
acpi_tb_set_table_loaded_flag(table_index, FALSE);
- /* Delete the table descriptor (ddb_handle) */
-
- acpi_ut_remove_reference(table_desc);
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 79f2c0d42c06..fd954b4ed83d 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 6e9a23e47fef..60e62c4f0577 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -96,6 +96,9 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
* to the original Node.
*/
switch (target_node->type) {
+
+ /* For these types, the sub-object can change dynamically via a Store */
+
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
@@ -103,9 +106,18 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
case ACPI_TYPE_BUFFER_FIELD:
/*
+ * These types open a new scope, so we need the NS node in order to access
+ * any children.
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_LOCAL_SCOPE:
+
+ /*
* The new alias has the type ALIAS and points to the original
- * NS node, not the object itself. This is because for these
- * types, the object can change dynamically via a Store.
+ * NS node, not the object itself.
*/
alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
alias_node->object =
@@ -115,9 +127,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
case ACPI_TYPE_METHOD:
/*
- * The new alias has the type ALIAS and points to the original
- * NS node, not the object itself. This is because for these
- * types, the object can change dynamically via a Store.
+ * Control method aliases need to be differentiated
*/
alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
alias_node->object =
@@ -342,101 +352,6 @@ acpi_ex_create_region(u8 * aml_start,
/*******************************************************************************
*
- * FUNCTION: acpi_ex_create_table_region
- *
- * PARAMETERS: walk_state - Current state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create a new data_table_region object
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
-{
- acpi_status status;
- union acpi_operand_object **operand = &walk_state->operands[0];
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
- union acpi_operand_object *region_obj2;
- acpi_native_uint table_index;
- struct acpi_table_header *table;
-
- ACPI_FUNCTION_TRACE(ex_create_table_region);
-
- /* Get the Node from the object stack */
-
- node = walk_state->op->common.node;
-
- /*
- * If the region object is already attached to this node,
- * just return
- */
- if (acpi_ns_get_attached_object(node)) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Find the ACPI table */
-
- status = acpi_tb_find_table(operand[1]->string.pointer,
- operand[2]->string.pointer,
- operand[3]->string.pointer, &table_index);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Create the region descriptor */
-
- obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
- if (!obj_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- 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;
- obj_desc->region.address =
- (acpi_physical_address) ACPI_TO_INTEGER(table);
- obj_desc->region.length = table->length;
- obj_desc->region.node = node;
- obj_desc->region.flags = AOPOBJ_DATA_VALID;
-
- /* Install the new region object in the parent Node */
-
- status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status = acpi_ev_initialize_region(obj_desc, FALSE);
- if (ACPI_FAILURE(status)) {
- if (status == AE_NOT_EXIST) {
- status = AE_OK;
- } else {
- goto cleanup;
- }
- }
-
- obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE;
-
- cleanup:
-
- /* Remove local reference to the object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_create_processor
*
* PARAMETERS: walk_state - Current state
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 51c9c29987c3..74f1b22601b3 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -500,25 +500,28 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
acpi_os_printf("Reference: Debug\n");
break;
- case AML_NAME_OP:
+ case AML_INDEX_OP:
- ACPI_DUMP_PATHNAME(obj_desc->reference.object,
- "Reference: Name: ", ACPI_LV_INFO,
- _COMPONENT);
- ACPI_DUMP_ENTRY(obj_desc->reference.object,
- ACPI_LV_INFO);
+ acpi_os_printf("Reference: Index %p\n",
+ obj_desc->reference.object);
break;
- case AML_INDEX_OP:
+ case AML_LOAD_OP:
- acpi_os_printf("Reference: Index %p\n",
+ acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n",
obj_desc->reference.object);
break;
case AML_REF_OF_OP:
- acpi_os_printf("Reference: (RefOf) %p\n",
- obj_desc->reference.object);
+ acpi_os_printf("Reference: (RefOf) %p [%s]\n",
+ obj_desc->reference.object,
+ acpi_ut_get_type_name(((union
+ acpi_operand_object
+ *)obj_desc->
+ reference.
+ object)->common.
+ type));
break;
case AML_ARG_OP:
@@ -559,8 +562,9 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case AML_INT_NAMEPATH_OP:
- acpi_os_printf("Reference.Node->Name %X\n",
- obj_desc->reference.node->name.integer);
+ acpi_os_printf("Reference: Namepath %X [%4.4s]\n",
+ obj_desc->reference.node->name.integer,
+ obj_desc->reference.node->name.ascii);
break;
default:
@@ -640,8 +644,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
acpi_os_printf("\n");
} else {
acpi_os_printf(" base %8.8X%8.8X Length %X\n",
- ACPI_FORMAT_UINT64(obj_desc->region.
- address),
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.
+ address),
obj_desc->region.length);
}
break;
@@ -877,20 +881,43 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) {
- acpi_os_printf("Named Object %p ", obj_desc->reference.node);
+ acpi_os_printf(" Named Object %p ", obj_desc->reference.node);
status =
acpi_ns_handle_to_pathname(obj_desc->reference.node,
&ret_buf);
if (ACPI_FAILURE(status)) {
- acpi_os_printf("Could not convert name to pathname\n");
+ acpi_os_printf(" Could not convert name to pathname\n");
} else {
acpi_os_printf("%s\n", (char *)ret_buf.pointer);
ACPI_FREE(ret_buf.pointer);
}
} else if (obj_desc->reference.object) {
- acpi_os_printf("\nReferenced Object: %p\n",
- obj_desc->reference.object);
+ if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) ==
+ ACPI_DESC_TYPE_OPERAND) {
+ acpi_os_printf(" Target: %p",
+ obj_desc->reference.object);
+ if (obj_desc->reference.opcode == AML_LOAD_OP) {
+ /*
+ * For DDBHandle reference,
+ * obj_desc->Reference.Object is the table index
+ */
+ acpi_os_printf(" [DDBHandle]\n");
+ } else {
+ acpi_os_printf(" [%s]\n",
+ acpi_ut_get_type_name(((union
+ acpi_operand_object
+ *)
+ obj_desc->
+ reference.
+ object)->
+ common.
+ type));
+ }
+ } else {
+ acpi_os_printf(" Target: %p\n",
+ obj_desc->reference.object);
+ }
}
}
@@ -976,7 +1003,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
case ACPI_TYPE_LOCAL_REFERENCE:
- acpi_os_printf("[Object Reference] ");
+ acpi_os_printf("[Object Reference] %s",
+ (acpi_ps_get_opcode_info
+ (obj_desc->reference.opcode))->name);
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 2d88a3d8d1ad..3e440d84226a 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,6 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
union acpi_operand_object *buffer_desc;
acpi_size length;
void *buffer;
- u8 locked;
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
@@ -111,9 +110,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.
- field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/*
* Perform the read.
@@ -125,7 +122,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
buffer.pointer),
ACPI_READ | (obj_desc->field.
attribute << 16));
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
goto exit;
}
@@ -175,13 +172,12 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Read from the field */
status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
exit:
if (ACPI_FAILURE(status)) {
@@ -214,10 +210,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
{
acpi_status status;
u32 length;
- u32 required_length;
void *buffer;
- void *new_buffer;
- u8 locked;
union acpi_operand_object *buffer_desc;
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -278,9 +271,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.
- field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/*
* Perform the write (returns status and perhaps data in the
@@ -291,7 +282,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
(acpi_integer *) buffer,
ACPI_WRITE | (obj_desc->field.
attribute << 16));
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
*result_desc = buffer_desc;
return_ACPI_STATUS(status);
@@ -319,35 +310,6 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /*
- * We must have a buffer that is at least as long as the field
- * we are writing to. This is because individual fields are
- * indivisible and partial writes are not supported -- as per
- * the ACPI specification.
- */
- new_buffer = NULL;
- required_length =
- ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
-
- if (length < required_length) {
-
- /* We need to create a new buffer */
-
- new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
- if (!new_buffer) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /*
- * Copy the original data to the new buffer, starting
- * at Byte zero. All unused (upper) bytes of the
- * buffer will be 0.
- */
- ACPI_MEMCPY((char *)new_buffer, (char *)buffer, length);
- buffer = new_buffer;
- length = required_length;
- }
-
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
source_desc,
@@ -366,19 +328,12 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Write to the field */
status = acpi_ex_insert_into_field(obj_desc, buffer, length);
- acpi_ex_release_global_lock(locked);
-
- /* Free temporary buffer if we used one */
-
- if (new_buffer) {
- ACPI_FREE(new_buffer);
- }
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 65a48b6170ee..e336b5dc7a50 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -263,7 +263,8 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
- field_datum_byte_offset, (void *)address));
+ field_datum_byte_offset, ACPI_CAST_PTR(void,
+ address)));
/* Invoke the appropriate address_space/op_region handler */
@@ -805,18 +806,39 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
u32 datum_count;
u32 field_datum_count;
u32 i;
+ u32 required_length;
+ void *new_buffer;
ACPI_FUNCTION_TRACE(ex_insert_into_field);
/* Validate input buffer */
- if (buffer_length <
- ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
- ACPI_ERROR((AE_INFO,
- "Field size %X (bits) is too large for buffer (%X)",
- obj_desc->common_field.bit_length, buffer_length));
+ new_buffer = NULL;
+ required_length =
+ ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
+ /*
+ * We must have a buffer that is at least as long as the field
+ * we are writing to. This is because individual fields are
+ * indivisible and partial writes are not supported -- as per
+ * the ACPI specification.
+ */
+ if (buffer_length < required_length) {
- return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
+ /* We need to create a new buffer */
+
+ new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
+ if (!new_buffer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the original data to the new buffer, starting
+ * at Byte zero. All unused (upper) bytes of the
+ * buffer will be 0.
+ */
+ ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length);
+ buffer = new_buffer;
+ buffer_length = required_length;
}
/*
@@ -866,7 +888,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
merged_datum,
field_offset);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
field_offset += obj_desc->common_field.access_byte_width;
@@ -924,5 +946,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
mask, merged_datum,
field_offset);
+ exit:
+ /* Free temporary buffer if we used one */
+
+ if (new_buffer) {
+ ACPI_FREE(new_buffer);
+ }
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index f13d1cec2d6d..cc956a5b5267 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 6748e3ef0997..c873ab40cd0e 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,6 +126,79 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
/*******************************************************************************
*
+ * FUNCTION: acpi_ex_acquire_mutex_object
+ *
+ * PARAMETERS: time_desc - Timeout in milliseconds
+ * obj_desc - Mutex object
+ * Thread - Current thread state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
+ * path that supports multiple acquires by the same thread.
+ *
+ * MUTEX: Interpreter must be locked
+ *
+ * NOTE: This interface is called from three places:
+ * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator
+ * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the
+ * global lock
+ * 3) From the external interface, acpi_acquire_global_lock
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_acquire_mutex_object(u16 timeout,
+ union acpi_operand_object *obj_desc,
+ acpi_thread_id thread_id)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc);
+
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Support for multiple acquires by the owning thread */
+
+ if (obj_desc->mutex.thread_id == 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);
+ }
+
+ /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_acquire_global_lock(timeout);
+ } else {
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ timeout);
+ }
+
+ if (ACPI_FAILURE(status)) {
+
+ /* Includes failure from a timeout on time_desc */
+
+ return_ACPI_STATUS(status);
+ }
+
+ /* Acquired the mutex: update mutex object */
+
+ obj_desc->mutex.thread_id = thread_id;
+ obj_desc->mutex.acquisition_depth = 1;
+ obj_desc->mutex.original_sync_level = 0;
+ obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ex_acquire_mutex
*
* PARAMETERS: time_desc - Timeout integer
@@ -151,7 +224,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 */
+ /* Must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -161,7 +234,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
}
/*
- * Current Sync must be less than or equal to the sync level of the
+ * Current sync level must be less than or equal to the sync level of the
* mutex. This mechanism provides some deadlock prevention
*/
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
@@ -172,51 +245,89 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Support for multiple acquires by the owning thread */
+ status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value,
+ obj_desc,
+ walk_state->thread->thread_id);
+ if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) {
- if (obj_desc->mutex.owner_thread) {
- if (obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->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);
- }
+ /* Save Thread object, original/current sync levels */
+
+ obj_desc->mutex.owner_thread = walk_state->thread;
+ obj_desc->mutex.original_sync_level =
+ walk_state->thread->current_sync_level;
+ walk_state->thread->current_sync_level =
+ obj_desc->mutex.sync_level;
+
+ /* Link the mutex to the current thread for force-unlock at method exit */
+
+ acpi_ex_link_mutex(obj_desc, walk_state->thread);
}
- /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+ return_ACPI_STATUS(status);
+}
- 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);
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_release_mutex_object
+ *
+ * PARAMETERS: obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release a previously acquired Mutex, low level interface.
+ * Provides a common path that supports multiple releases (after
+ * previous multiple acquires) by the same thread.
+ *
+ * MUTEX: Interpreter must be locked
+ *
+ * NOTE: This interface is called from three places:
+ * 1) From acpi_ex_release_mutex, via an AML Acquire() operator
+ * 2) From acpi_ex_release_global_lock when an AML Field access requires the
+ * global lock
+ * 3) From the external interface, acpi_release_global_lock
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ex_release_mutex_object);
+
+ if (obj_desc->mutex.acquisition_depth == 0) {
+ return (AE_NOT_ACQUIRED);
}
- if (ACPI_FAILURE(status)) {
+ /* Match multiple Acquires with multiple Releases */
- /* Includes failure from a timeout on time_desc */
+ obj_desc->mutex.acquisition_depth--;
+ if (obj_desc->mutex.acquisition_depth != 0) {
- return_ACPI_STATUS(status);
+ /* Just decrement the depth and return */
+
+ return_ACPI_STATUS(AE_OK);
}
- /* Have the mutex: update mutex and walk info and save the sync_level */
+ if (obj_desc->mutex.owner_thread) {
- obj_desc->mutex.owner_thread = walk_state->thread;
- obj_desc->mutex.acquisition_depth = 1;
- obj_desc->mutex.original_sync_level =
- walk_state->thread->current_sync_level;
+ /* Unlink the mutex from the owner's list */
- walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
+ acpi_ex_unlink_mutex(obj_desc);
+ obj_desc->mutex.owner_thread = NULL;
+ }
- /* Link the mutex to the current thread for force-unlock at method exit */
+ /* Release the mutex, special case for Global Lock */
- acpi_ex_link_mutex(obj_desc, walk_state->thread);
- return_ACPI_STATUS(AE_OK);
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ }
+
+ /* Clear mutex info */
+
+ obj_desc->mutex.thread_id = 0;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -253,22 +364,13 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Sanity check: we must have a valid thread ID */
-
- if (!walk_state->thread) {
- ACPI_ERROR((AE_INFO,
- "Cannot release Mutex [%4.4s], null thread info",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
- return_ACPI_STATUS(AE_AML_INTERNAL);
- }
-
/*
* 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 !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
+ && (obj_desc != 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,
@@ -278,45 +380,37 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
+ /* Must have a valid thread ID */
+
+ if (!walk_state->thread) {
+ ACPI_ERROR((AE_INFO,
+ "Cannot release Mutex [%4.4s], null thread info",
+ acpi_ut_get_node_name(obj_desc->mutex.node)));
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
/*
* 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,
- "Cannot release Mutex [%4.4s], incorrect SyncLevel",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
+ "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
+ acpi_ut_get_node_name(obj_desc->mutex.node),
+ obj_desc->mutex.sync_level,
+ walk_state->thread->current_sync_level));
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Match multiple Acquires with multiple Releases */
-
- obj_desc->mutex.acquisition_depth--;
- if (obj_desc->mutex.acquisition_depth != 0) {
-
- /* Just decrement the depth and return */
-
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Unlink the mutex from the owner's list */
+ status = acpi_ex_release_mutex_object(obj_desc);
- acpi_ex_unlink_mutex(obj_desc);
+ if (obj_desc->mutex.acquisition_depth == 0) {
- /* Release the mutex, special case for Global Lock */
+ /* Restore the original sync_level */
- 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);
+ walk_state->thread->current_sync_level =
+ obj_desc->mutex.original_sync_level;
}
-
- /* Update the mutex and restore sync_level */
-
- obj_desc->mutex.owner_thread = NULL;
- walk_state->thread->current_sync_level =
- obj_desc->mutex.original_sync_level;
-
return_ACPI_STATUS(status);
}
@@ -357,7 +451,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Release the mutex, special case for Global Lock */
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
/* Ignore errors */
@@ -369,6 +463,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Mark mutex unowned */
obj_desc->mutex.owner_thread = NULL;
+ obj_desc->mutex.thread_id = 0;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index 308eae52dc05..817e67be3697 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 252f10acbbcc..7c3bea575e02 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
if ((ACPI_FAILURE(status)) || walk_state->result_obj) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
} else {
/* Save the return value */
@@ -739,26 +740,38 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
value = acpi_gbl_integer_byte_width;
break;
- case ACPI_TYPE_BUFFER:
- value = temp_desc->buffer.length;
- break;
-
case ACPI_TYPE_STRING:
value = temp_desc->string.length;
break;
+ case ACPI_TYPE_BUFFER:
+
+ /* Buffer arguments may not be evaluated at this point */
+
+ status = acpi_ds_get_buffer_arguments(temp_desc);
+ value = temp_desc->buffer.length;
+ break;
+
case ACPI_TYPE_PACKAGE:
+
+ /* Package arguments may not be evaluated at this point */
+
+ status = acpi_ds_get_package_arguments(temp_desc);
value = temp_desc->package.count;
break;
default:
ACPI_ERROR((AE_INFO,
- "Operand is not Buf/Int/Str/Pkg - found type %s",
+ "Operand must be Buffer/Integer/String/Package - found type %s",
acpi_ut_get_type_name(type)));
status = AE_AML_OPERAND_TYPE;
goto cleanup;
}
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
/*
* Now that we have the size of the object, create a result
* object to hold the value
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 17e652e65379..8e8bbb6ccebd 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -241,10 +241,6 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
goto cleanup;
}
- /* Return the remainder */
-
- walk_state->result_obj = return_desc1;
-
cleanup:
/*
* Since the remainder is not returned indirectly, remove a reference to
@@ -259,6 +255,12 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
acpi_ut_remove_reference(return_desc1);
}
+ /* Save return object (the remainder) on success */
+
+ else {
+ walk_state->result_obj = return_desc1;
+ }
+
return_ACPI_STATUS(status);
}
@@ -490,6 +492,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
}
return_ACPI_STATUS(status);
@@ -583,8 +586,6 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
return_desc->integer.value = ACPI_INTEGER_MAX;
}
- walk_state->result_obj = return_desc;
-
cleanup:
/* Delete return object on error */
@@ -593,5 +594,11 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index 7fe67cf82cee..9cb4197681af 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -260,6 +260,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status) || walk_state->result_obj) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
}
/* Set the return object and exit */
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index bd80a9cb3d65..67d48737af53 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -322,8 +322,6 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
goto cleanup;
}
- walk_state->result_obj = return_desc;
-
cleanup:
/* Delete return object on error */
@@ -332,5 +330,11 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index efe5d4b461a4..3a2f8cd4c62a 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -412,6 +412,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *second_desc = NULL;
u32 type;
acpi_status status;
@@ -494,6 +495,20 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
obj_desc->field.access_byte_width,
obj_desc->bank_field.region_obj,
obj_desc->bank_field.bank_obj));
+
+ /*
+ * Remember location in AML stream of the field unit
+ * opcode and operands -- since the bank_value
+ * operands must be evaluated.
+ */
+ second_desc = obj_desc->common.next_object;
+ second_desc->extra.aml_start =
+ ((union acpi_parse_object *)(info->data_register_node))->
+ named.data;
+ second_desc->extra.aml_length =
+ ((union acpi_parse_object *)(info->data_register_node))->
+ named.length;
+
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3f51b7e84a17..7cd8bb54fa01 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -160,7 +160,7 @@ acpi_ex_system_memory_space_handler(u32 function,
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),
+ ACPI_FORMAT_NATIVE_UINT(address),
(u32) window_size));
mem_info->mapped_length = 0;
return_ACPI_STATUS(AE_NO_MEMORY);
@@ -182,7 +182,8 @@ acpi_ex_system_memory_space_handler(u32 function,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
- bit_width, function, ACPI_FORMAT_UINT64(address)));
+ bit_width, function,
+ ACPI_FORMAT_NATIVE_UINT(address)));
/*
* Perform the memory read or write
@@ -284,7 +285,8 @@ acpi_ex_system_io_space_handler(u32 function,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-IO (width %d) R/W %d Address=%8.8X%8.8X\n",
- bit_width, function, ACPI_FORMAT_UINT64(address)));
+ bit_width, function,
+ ACPI_FORMAT_NATIVE_UINT(address)));
/* Decode the function parameter */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 2b3a01cc4929..5596f42c9676 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,9 +116,11 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
* Several object types require no further processing:
* 1) Device/Thermal objects don't have a "real" subobject, return the Node
* 2) Method locals and arguments have a pseudo-Node
+ * 3) 10/2007: Added method type to assist with Package construction.
*/
if ((entry_type == ACPI_TYPE_DEVICE) ||
(entry_type == ACPI_TYPE_THERMAL) ||
+ (entry_type == ACPI_TYPE_METHOD) ||
(node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) {
return_ACPI_STATUS(AE_OK);
}
@@ -214,7 +216,6 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
/* For these objects, just return the object attached to the Node */
case ACPI_TYPE_MUTEX:
- case ACPI_TYPE_METHOD:
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_EVENT:
@@ -238,13 +239,12 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
case ACPI_TYPE_LOCAL_REFERENCE:
switch (source_desc->reference.opcode) {
- case AML_LOAD_OP:
+ case AML_LOAD_OP: /* This is a ddb_handle */
+ case AML_REF_OF_OP:
+ case AML_INDEX_OP:
- /* This is a ddb_handle */
/* Return an additional reference to the object */
- case AML_REF_OF_OP:
-
obj_desc = source_desc;
acpi_ut_add_reference(obj_desc);
break;
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6c64e55dab0e..b35f7c817acf 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -140,7 +140,6 @@ 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 = NULL;
u16 opcode;
@@ -156,23 +155,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
opcode = stack_desc->reference.opcode;
switch (opcode) {
- case AML_NAME_OP:
-
- /*
- * Convert name reference to a namespace node
- * Then, acpi_ex_resolve_node_to_value can be used to get the value
- */
- temp_node = stack_desc->reference.object;
-
- /* Delete the Reference Object */
-
- acpi_ut_remove_reference(stack_desc);
-
- /* Return the namespace node */
-
- (*stack_ptr) = temp_node;
- break;
-
case AML_LOCAL_OP:
case AML_ARG_OP:
@@ -207,15 +189,25 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
switch (stack_desc->reference.target_type) {
case ACPI_TYPE_BUFFER_FIELD:
- /* Just return - leave the Reference on the stack */
+ /* Just return - do not dereference */
break;
case ACPI_TYPE_PACKAGE:
+ /* If method call or copy_object - do not dereference */
+
+ if ((walk_state->opcode ==
+ AML_INT_METHODCALL_OP)
+ || (walk_state->opcode == AML_COPY_OP)) {
+ break;
+ }
+
+ /* Otherwise, dereference the package_index to a package element */
+
obj_desc = *stack_desc->reference.where;
if (obj_desc) {
/*
- * Valid obj descriptor, copy pointer to return value
+ * Valid object descriptor, copy pointer to return value
* (i.e., dereference the package index)
* Delete the ref object, increment the returned object
*/
@@ -224,11 +216,11 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
*stack_ptr = obj_desc;
} else {
/*
- * A NULL object descriptor means an unitialized element of
+ * A NULL object descriptor means an uninitialized element of
* the package, can't dereference it
*/
ACPI_ERROR((AE_INFO,
- "Attempt to deref an Index to NULL pkg element Idx=%p",
+ "Attempt to dereference an Index to NULL package element Idx=%p",
stack_desc));
status = AE_AML_UNINITIALIZED_ELEMENT;
}
@@ -239,7 +231,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
/* Invalid reference object */
ACPI_ERROR((AE_INFO,
- "Unknown TargetType %X in Index/Reference obj %p",
+ "Unknown TargetType %X in Index/Reference object %p",
stack_desc->reference.target_type,
stack_desc));
status = AE_AML_INTERNAL;
@@ -251,7 +243,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
case AML_DEBUG_OP:
case AML_LOAD_OP:
- /* Just leave the object as-is */
+ /* Just leave the object as-is, do not dereference */
break;
@@ -390,10 +382,10 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
/*
- * For reference objects created via the ref_of or Index operators,
- * we need to get to the base object (as per the ACPI specification
- * of the object_type and size_of operators). This means traversing
- * the list of possibly many nested references.
+ * For reference objects created via the ref_of, Index, or Load/load_table
+ * operators, we need to get to the base object (as per the ACPI
+ * specification of the object_type and size_of operators). This means
+ * traversing the list of possibly many nested references.
*/
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
switch (obj_desc->reference.opcode) {
@@ -463,6 +455,11 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
break;
+ case AML_LOAD_OP:
+
+ type = ACPI_TYPE_DDB_HANDLE;
+ goto exit;
+
case AML_LOCAL_OP:
case AML_ARG_OP:
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 09d897b3f6d5..73e29e566a70 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -137,7 +137,6 @@ acpi_ex_resolve_operands(u16 opcode,
union acpi_operand_object *obj_desc;
acpi_status status = AE_OK;
u8 object_type;
- void *temp_node;
u32 arg_types;
const struct acpi_opcode_info *op_info;
u32 this_arg_type;
@@ -239,7 +238,6 @@ acpi_ex_resolve_operands(u16 opcode,
/*lint -fallthrough */
- case AML_NAME_OP:
case AML_INDEX_OP:
case AML_REF_OF_OP:
case AML_ARG_OP:
@@ -332,15 +330,6 @@ acpi_ex_resolve_operands(u16 opcode,
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
- if (obj_desc->reference.opcode == AML_NAME_OP) {
-
- /* Convert a named reference to the actual named object */
-
- temp_node = obj_desc->reference.object;
- acpi_ut_remove_reference(obj_desc);
- (*stack_ptr) = temp_node;
- }
goto next_operand;
case ARGI_DATAREFOBJ: /* Store operator only */
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index f4b69a637820..76c875bc3154 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,8 +84,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc);
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
- level, " "));
+ /* Print line header as long as we are not in the middle of an object display */
+
+ if (!((level > 0) && index == 0)) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
+ level, " "));
+ }
/* Display index for package output only */
@@ -95,12 +99,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
}
if (!source_desc) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "<Null Object>\n"));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[Null Object]\n"));
return_VOID;
}
if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s: ",
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s ",
acpi_ut_get_object_type_name
(source_desc)));
@@ -123,6 +127,8 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
return_VOID;
}
+ /* source_desc is of type ACPI_DESC_TYPE_OPERAND */
+
switch (ACPI_GET_OBJECT_TYPE(source_desc)) {
case ACPI_TYPE_INTEGER:
@@ -147,7 +153,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
(u32) source_desc->buffer.length));
ACPI_DUMP_BUFFER(source_desc->buffer.pointer,
(source_desc->buffer.length <
- 32) ? source_desc->buffer.length : 32);
+ 256) ? source_desc->buffer.length : 256);
break;
case ACPI_TYPE_STRING:
@@ -160,7 +166,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
case ACPI_TYPE_PACKAGE:
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
- "[0x%.2X Elements]\n",
+ "[Contains 0x%.2X Elements]\n",
source_desc->package.count));
/* Output the entire contents of the package */
@@ -180,12 +186,59 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
(source_desc->reference.opcode),
source_desc->reference.offset));
} else {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]\n",
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]",
acpi_ps_get_opcode_name
(source_desc->reference.opcode)));
}
- if (source_desc->reference.object) {
+ if (source_desc->reference.opcode == AML_LOAD_OP) { /* Load and load_table */
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ " Table OwnerId %p\n",
+ source_desc->reference.object));
+ break;
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, " "));
+
+ /* Check for valid node first, then valid object */
+
+ if (source_desc->reference.node) {
+ if (ACPI_GET_DESCRIPTOR_TYPE
+ (source_desc->reference.node) !=
+ ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ " %p - Not a valid namespace node\n",
+ source_desc->reference.
+ node));
+ } else {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ "Node %p [%4.4s] ",
+ source_desc->reference.
+ node,
+ (source_desc->reference.
+ node)->name.ascii));
+
+ switch ((source_desc->reference.node)->type) {
+
+ /* These types have no attached object */
+
+ case ACPI_TYPE_DEVICE:
+ acpi_os_printf("Device\n");
+ break;
+
+ case ACPI_TYPE_THERMAL:
+ acpi_os_printf("Thermal Zone\n");
+ break;
+
+ default:
+ acpi_ex_do_debug_object((source_desc->
+ reference.
+ node)->object,
+ level + 4, 0);
+ break;
+ }
+ }
+ } else if (source_desc->reference.object) {
if (ACPI_GET_DESCRIPTOR_TYPE
(source_desc->reference.object) ==
ACPI_DESC_TYPE_NAMED) {
@@ -198,18 +251,13 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
acpi_ex_do_debug_object(source_desc->reference.
object, level + 4, 0);
}
- } else if (source_desc->reference.node) {
- acpi_ex_do_debug_object((source_desc->reference.node)->
- object, level + 4, 0);
}
break;
default:
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p %s\n",
- source_desc,
- acpi_ut_get_object_type_name
- (source_desc)));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p\n",
+ source_desc));
break;
}
@@ -313,7 +361,6 @@ acpi_ex_store(union acpi_operand_object *source_desc,
* 4) Store to the debug object
*/
switch (ref_desc->reference.opcode) {
- case AML_NAME_OP:
case AML_REF_OF_OP:
/* Storing an object into a Name "container" */
@@ -415,11 +462,24 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
*/
obj_desc = *(index_desc->reference.where);
- status =
- acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
- walk_state);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if (ACPI_GET_OBJECT_TYPE(source_desc) ==
+ ACPI_TYPE_LOCAL_REFERENCE
+ && source_desc->reference.opcode == AML_LOAD_OP) {
+
+ /* This is a DDBHandle, just add a reference to it */
+
+ acpi_ut_add_reference(source_desc);
+ new_desc = source_desc;
+ } else {
+ /* Normal object, copy it */
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(source_desc,
+ &new_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
if (obj_desc) {
@@ -571,10 +631,17 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
/* If no implicit conversion, drop into the default case below */
- if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {
-
- /* Force execution of default (no implicit conversion) */
-
+ if ((!implicit_conversion) ||
+ ((walk_state->opcode == AML_COPY_OP) &&
+ (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) &&
+ (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) &&
+ (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) {
+ /*
+ * Force execution of default (no implicit conversion). Note:
+ * copy_object does not perform an implicit conversion, as per the ACPI
+ * spec -- except in case of region/bank/index fields -- because these
+ * objects must retain their original type permanently.
+ */
target_type = ACPI_TYPE_ANY;
}
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 1d622c625c64..a6d2168b81f9 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 8233d40178ee..9a75ff09fb0c 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 9460baff3032..68990f1df371 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
-#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exsystem")
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 6b0aeccbb69b..86c03880b523 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
-#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exutils")
@@ -217,9 +216,10 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
/*
* Object must be a valid number and we must be executing
- * a control method
+ * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
*/
if ((!obj_desc) ||
+ (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) ||
(ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) {
return;
}
@@ -240,72 +240,73 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
* PARAMETERS: field_flags - Flags with Lock rule:
* always_lock or never_lock
*
- * RETURN: TRUE/FALSE indicating whether the lock was actually acquired
+ * RETURN: None
*
- * DESCRIPTION: Obtain the global lock and keep track of this fact via two
- * methods. A global variable keeps the state of the lock, and
- * the state is returned to the caller.
+ * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
+ * flags specifiy that it is to be obtained before field access.
*
******************************************************************************/
-u8 acpi_ex_acquire_global_lock(u32 field_flags)
+void acpi_ex_acquire_global_lock(u32 field_flags)
{
- u8 locked = FALSE;
acpi_status status;
ACPI_FUNCTION_TRACE(ex_acquire_global_lock);
- /* Only attempt lock if the always_lock bit is set */
+ /* Only use the lock if the always_lock bit is set */
+
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
+ }
- if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
+ /* Attempt to get the global lock, wait forever */
- /* We should attempt to get the lock, wait forever */
+ status = acpi_ex_acquire_mutex_object(ACPI_WAIT_FOREVER,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
- status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
- if (ACPI_SUCCESS(status)) {
- locked = TRUE;
- } else {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire Global Lock"));
- }
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not acquire Global Lock"));
}
- return_UINT8(locked);
+ return_VOID;
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_release_global_lock
*
- * PARAMETERS: locked_by_me - Return value from corresponding call to
- * acquire_global_lock.
+ * PARAMETERS: field_flags - Flags with Lock rule:
+ * always_lock or never_lock
*
* RETURN: None
*
- * DESCRIPTION: Release the global lock if it is locked.
+ * DESCRIPTION: Release the ACPI hardware Global Lock
*
******************************************************************************/
-void acpi_ex_release_global_lock(u8 locked_by_me)
+void acpi_ex_release_global_lock(u32 field_flags)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ex_release_global_lock);
- /* Only attempt unlock if the caller locked it */
+ /* Only use the lock if the always_lock bit is set */
- if (locked_by_me) {
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
+ }
- /* OK, now release the lock */
+ /* Release the global lock */
- status = acpi_ev_release_global_lock();
- if (ACPI_FAILURE(status)) {
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
+ if (ACPI_FAILURE(status)) {
- /* Report the error, but there isn't much else we can do */
+ /* Report the error, but there isn't much else we can do */
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not release ACPI Global Lock"));
- }
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not release Global Lock"));
}
return_VOID;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index c8e3cba423ef..6cf10cbc1eee 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -192,17 +192,13 @@ static int acpi_fan_add_fs(struct acpi_device *device)
}
/* 'status' [R/W] */
- entry = create_proc_entry(ACPI_FAN_FILE_STATE,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_FAN_FILE_STATE,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_fan_state_ops,
+ device);
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_fan_state_ops;
- entry->data = device;
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
@@ -260,24 +256,23 @@ static int acpi_fan_add(struct acpi_device *device)
result = PTR_ERR(cdev);
goto end;
}
- if (cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev.bus_id, cdev->id);
-
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
-
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- return result;
- }
+
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, cdev->id);
+
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
result = acpi_fan_add_fs(device);
if (result)
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index eda0978b57c6..06f8634fe58b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -142,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device);
static int acpi_bind_one(struct device *dev, acpi_handle handle)
{
+ struct acpi_device *acpi_dev;
acpi_status status;
if (dev->archdata.acpi_handle) {
@@ -157,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
}
dev->archdata.acpi_handle = handle;
+ status = acpi_bus_get_device(handle, &acpi_dev);
+ if (!ACPI_FAILURE(status)) {
+ int ret;
+
+ ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
+ "firmware_node");
+ ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
+ "physical_node");
+ }
+
return 0;
}
@@ -165,8 +176,17 @@ static int acpi_unbind_one(struct device *dev)
if (!dev->archdata.acpi_handle)
return 0;
if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
+ struct acpi_device *acpi_dev;
+
/* acpi_get_physical_device increase refcnt by one */
put_device(dev);
+
+ if (!acpi_bus_get_device(dev->archdata.acpi_handle,
+ &acpi_dev)) {
+ sysfs_remove_link(&dev->kobj, "firmware_node");
+ sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
+ }
+
acpi_detach_data(dev->archdata.acpi_handle,
acpi_glue_data_handler);
dev->archdata.acpi_handle = NULL;
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index 6031ca13dd2f..816894ea839e 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 117a05cadaaa..14bc4f456ae8 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index 73f9c5fb1ba7..ddf792adcf96 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 4290e0193097..d9937e05ec6a 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,9 +70,10 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
/* Get the FACS */
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -124,9 +125,10 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
/* Get the FACS */
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c32eab696acd..b53d575491b9 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index 57faf598bad8..c39a7f68b889 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -208,8 +208,7 @@ acpi_status acpi_ns_root_initialize(void)
/* Special case for ACPI Global Lock */
if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
- acpi_gbl_global_lock_mutex =
- obj_desc->mutex.os_mutex;
+ acpi_gbl_global_lock_mutex = obj_desc;
/* Create additional counting semaphore for global lock */
@@ -582,44 +581,68 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
return_ACPI_STATUS(status);
}
- /*
- * Sanity typecheck of the target object:
- *
- * If 1) This is the last segment (num_segments == 0)
- * 2) And we are looking for a specific type
- * (Not checking for TYPE_ANY)
- * 3) Which is not an alias
- * 4) Which is not a local type (TYPE_SCOPE)
- * 5) And the type of target object is known (not TYPE_ANY)
- * 6) And target object does not match what we are looking for
- *
- * Then we have a type mismatch. Just warn and ignore it.
- */
- if ((num_segments == 0) &&
- (type_to_check_for != ACPI_TYPE_ANY) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) &&
- (this_node->type != ACPI_TYPE_ANY) &&
- (this_node->type != type_to_check_for)) {
-
- /* Complain about a type mismatch */
-
- ACPI_WARNING((AE_INFO,
- "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
- ACPI_CAST_PTR(char, &simple_name),
- acpi_ut_get_type_name(this_node->type),
- acpi_ut_get_type_name
- (type_to_check_for)));
+ /* More segments to follow? */
+
+ if (num_segments > 0) {
+ /*
+ * If we have an alias to an object that opens a scope (such as a
+ * device or processor), we need to dereference the alias here so that
+ * we can access any children of the original node (via the remaining
+ * segments).
+ */
+ if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) {
+ if (acpi_ns_opens_scope
+ (((struct acpi_namespace_node *)this_node->
+ object)->type)) {
+ this_node =
+ (struct acpi_namespace_node *)
+ this_node->object;
+ }
+ }
}
- /*
- * If this is the last name segment and we are not looking for a
- * specific type, but the type of found object is known, use that type
- * to see if it opens a scope.
- */
- if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) {
- type = this_node->type;
+ /* Special handling for the last segment (num_segments == 0) */
+
+ else {
+ /*
+ * Sanity typecheck of the target object:
+ *
+ * If 1) This is the last segment (num_segments == 0)
+ * 2) And we are looking for a specific type
+ * (Not checking for TYPE_ANY)
+ * 3) Which is not an alias
+ * 4) Which is not a local type (TYPE_SCOPE)
+ * 5) And the type of target object is known (not TYPE_ANY)
+ * 6) And target object does not match what we are looking for
+ *
+ * Then we have a type mismatch. Just warn and ignore it.
+ */
+ if ((type_to_check_for != ACPI_TYPE_ANY) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS)
+ && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE)
+ && (this_node->type != ACPI_TYPE_ANY)
+ && (this_node->type != type_to_check_for)) {
+
+ /* Complain about a type mismatch */
+
+ ACPI_WARNING((AE_INFO,
+ "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
+ ACPI_CAST_PTR(char, &simple_name),
+ acpi_ut_get_type_name(this_node->
+ type),
+ acpi_ut_get_type_name
+ (type_to_check_for)));
+ }
+
+ /*
+ * If this is the last name segment and we are not looking for a
+ * specific type, but the type of found object is known, use that type
+ * to (later) see if it opens a scope.
+ */
+ if (type == ACPI_TYPE_ANY) {
+ type = this_node->type;
+ }
}
/* Point to next name segment and make this node current */
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 1d693d8ad2d8..3a1740ac2edc 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index 1fc4f86676e1..5445751b8a3e 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -249,7 +249,9 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
acpi_os_printf("ID %X Len %.4X Addr %p\n",
obj_desc->processor.proc_id,
obj_desc->processor.length,
- (char *)obj_desc->processor.address);
+ ACPI_CAST_PTR(void,
+ obj_desc->processor.
+ address));
break;
case ACPI_TYPE_DEVICE:
@@ -320,9 +322,8 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
space_id));
if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n",
- ACPI_FORMAT_UINT64(obj_desc->
- region.
- address),
+ ACPI_FORMAT_NATIVE_UINT
+ (obj_desc->region.address),
obj_desc->region.length);
} else {
acpi_os_printf
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index 5097e167939e..428f50fde11a 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 97b2ac57c16b..14bdfa92bea0 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index 33db2241044e..6d6d930c8e18 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -244,6 +244,10 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
info->field_count++;
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ info->field_count++;
+ break;
+
case ACPI_TYPE_BUFFER:
info->buffer_count++;
break;
@@ -287,6 +291,12 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
status = acpi_ds_get_buffer_field_arguments(obj_desc);
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ info->field_init++;
+ status = acpi_ds_get_bank_field_arguments(obj_desc);
+ break;
+
case ACPI_TYPE_BUFFER:
info->buffer_init++;
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index d4f9654fd20f..2c92f6cf5ce1 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,11 +107,11 @@ acpi_ns_load_table(acpi_native_uint table_index,
goto unlock;
}
- status = acpi_ns_parse_table(table_index, node->child);
+ status = acpi_ns_parse_table(table_index, node);
if (ACPI_SUCCESS(status)) {
acpi_tb_set_table_loaded_flag(table_index, TRUE);
} else {
- acpi_tb_release_owner_id(table_index);
+ (void)acpi_tb_release_owner_id(table_index);
}
unlock:
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index cbd94af08cc5..cffef1bcbdbc 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -180,6 +180,12 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
next_node = node;
while (next_node && (next_node != acpi_gbl_root_node)) {
+ if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid NS Node (%p) while traversing path",
+ next_node));
+ return 0;
+ }
size += ACPI_PATH_SEGMENT_LENGTH;
next_node = acpi_ns_get_parent_node(next_node);
}
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index d9d7377bc6e6..15fe09e24f71 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 e696aa847990..46a79b0103b6 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,8 @@ ACPI_MODULE_NAME("nsparse")
******************************************************************************/
acpi_status
acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index)
+ acpi_native_uint table_index,
+ struct acpi_namespace_node * start_node)
{
union acpi_parse_object *parse_root;
acpi_status status;
@@ -111,14 +112,25 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number,
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);
+ aml_start, (u32) 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);
+ goto cleanup;
+ }
+
+ /* start_node is the default location to load the table */
+
+ if (start_node && start_node != acpi_gbl_root_node) {
+ status =
+ acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
}
/* Parse the AML */
@@ -127,6 +139,7 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number,
(unsigned)pass_number));
status = acpi_ps_parse_aml(walk_state);
+ cleanup:
acpi_ps_delete_parse_tree(parse_root);
return_ACPI_STATUS(status);
}
@@ -163,7 +176,9 @@ acpi_ns_parse_table(acpi_native_uint table_index,
* performs another complete parse of the AML.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
- status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
+ status =
+ acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index,
+ start_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -178,7 +193,9 @@ acpi_ns_parse_table(acpi_native_uint table_index,
* parse objects are all cached.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
- status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
+ status =
+ acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index,
+ start_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index e863be665ce8..8399276cba1e 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 90fd059615ff..64c039843ed2 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index 280b8357c46c..3c905ce26d7d 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,9 +77,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct
/* It's really the parent's _scope_ that we want */
- if (parent_node->child) {
- next_node = parent_node->child;
- }
+ next_node = parent_node->child;
}
else {
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index b92133faf5b7..a8d549187c84 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -467,10 +467,13 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
return (AE_CTRL_DEPTH);
}
- if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
-
- /* Don't examine children of the device if not present */
-
+ if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
+ !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
+ /*
+ * Don't examine the children of the device only when the
+ * device is neither present nor functional. See ACPI spec,
+ * description of _STA for more information.
+ */
return (AE_CTRL_DEPTH);
}
@@ -539,7 +542,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
* value is returned to the caller.
*
* This is a wrapper for walk_namespace, but the callback performs
- * additional filtering. Please see acpi_get_device_callback.
+ * additional filtering. Please see acpi_ns_get_device_callback.
*
******************************************************************************/
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index b489781b22a8..a287ed550f54 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index faa375887201..2b375ee80cef 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index a498a6cc68fe..235a1386888a 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -742,6 +742,7 @@ EXPORT_SYMBOL(acpi_os_execute);
void acpi_os_wait_events_complete(void *context)
{
flush_workqueue(kacpid_wq);
+ flush_workqueue(kacpi_notify_wq);
}
EXPORT_SYMBOL(acpi_os_wait_events_complete);
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index c2b9835c890b..f1e8bf65e24e 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -230,12 +230,12 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
struct acpi_parse_state *parser_state,
union acpi_parse_object *arg, u8 possible_method_call)
{
+ acpi_status status;
char *path;
union acpi_parse_object *name_op;
- acpi_status status;
union acpi_operand_object *method_desc;
struct acpi_namespace_node *node;
- union acpi_generic_state scope_info;
+ u8 *start = parser_state->aml;
ACPI_FUNCTION_TRACE(ps_get_next_namepath);
@@ -249,25 +249,18 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_OK);
}
- /* Setup search scope info */
-
- scope_info.scope.node = NULL;
- node = parser_state->start_node;
- if (node) {
- scope_info.scope.node = node;
- }
-
/*
- * Lookup the name in the internal namespace. We don't want to add
- * anything new to the namespace here, however, so we use MODE_EXECUTE.
+ * Lookup the name in the internal namespace, starting with the current
+ * scope. We don't want to add anything new to the namespace here,
+ * however, so we use MODE_EXECUTE.
* Allow searching of the parent tree, but don't open a new scope -
* we just want to lookup the object (must be mode EXECUTE to perform
* the upsearch)
*/
- status =
- acpi_ns_lookup(&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
- ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
- NULL, &node);
+ status = acpi_ns_lookup(walk_state->scope_info, path,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ NULL, &node);
/*
* If this name is a control method invocation, we must
@@ -275,6 +268,16 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
+ if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ /*
+ * acpi_ps_get_next_namestring has increased the AML pointer,
+ * so we need to restore the saved AML pointer for method call.
+ */
+ walk_state->parser_state.aml = start;
+ walk_state->arg_count = 1;
+ acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
+ return_ACPI_STATUS(AE_OK);
+ }
/* This name is actually a control method invocation */
@@ -686,9 +689,29 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status =
- acpi_ps_get_next_namepath(walk_state, parser_state,
- arg, 0);
+ /* To support super_name arg of Unload */
+
+ if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ parser_state, arg,
+ 1);
+
+ /*
+ * If the super_name arg of Unload is a method call,
+ * we have restored the AML pointer, just free this Arg
+ */
+ if (arg->common.aml_opcode ==
+ AML_INT_METHODCALL_OP) {
+ acpi_ps_free_op(arg);
+ arg = NULL;
+ }
+ } else {
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ parser_state, arg,
+ 0);
+ }
} else {
/* Single complex argument, nothing returned */
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index 773aee82fbb8..c06238e55d98 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -182,6 +182,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.arg_list_length = 0;
unnamed_op->common.aml_opcode = walk_state->opcode;
/*
@@ -241,7 +242,8 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
acpi_gbl_depth++;
- if ((*op)->common.aml_opcode == AML_REGION_OP) {
+ if ((*op)->common.aml_opcode == AML_REGION_OP ||
+ (*op)->common.aml_opcode == AML_DATA_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.,
@@ -280,6 +282,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
acpi_status status = AE_OK;
union acpi_parse_object *op;
union acpi_parse_object *named_op = NULL;
+ union acpi_parse_object *parent_scope;
+ u8 argument_count;
+ const struct acpi_opcode_info *op_info;
ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
@@ -320,8 +325,32 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
op->named.length = 0;
}
- acpi_ps_append_arg(acpi_ps_get_parent_scope
- (&(walk_state->parser_state)), op);
+ if (walk_state->opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+
+ parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
+ acpi_ps_append_arg(parent_scope, op);
+
+ if (parent_scope) {
+ op_info =
+ acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
+ if (op_info->flags & AML_HAS_TARGET) {
+ argument_count =
+ acpi_ps_get_argument_count(op_info->type);
+ if (parent_scope->common.arg_list_length >
+ argument_count) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ }
if (walk_state->descending_callback != NULL) {
/*
@@ -603,13 +632,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
acpi_ps_pop_scope(&(walk_state->parser_state), op,
&walk_state->arg_types,
&walk_state->arg_count);
-
- 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 */
@@ -640,10 +662,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
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_ut_delete_generic_state
(acpi_ut_pop_generic_state
@@ -1005,7 +1023,8 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
acpi_gbl_depth--;
}
- if (op->common.aml_opcode == AML_REGION_OP) {
+ if (op->common.aml_opcode == AML_REGION_OP ||
+ op->common.aml_opcode == AML_DATA_REGION_OP) {
/*
* Skip parsing of control method or opregion body,
* because we don't have enough info in the first pass
@@ -1030,6 +1049,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
(u32) (parser_state->aml - op->named.data);
}
+ if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ *
+ * 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) {
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 9296e86761d7..f425ab30eae8 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,9 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psopcode")
+static const u8 acpi_gbl_argument_count[] =
+ { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
+
/*******************************************************************************
*
* NAME: acpi_gbl_aml_op_info
@@ -59,6 +62,7 @@ ACPI_MODULE_NAME("psopcode")
* the operand type.
*
******************************************************************************/
+
/*
* Summary of opcode types/flags
*
@@ -176,6 +180,7 @@ ACPI_MODULE_NAME("psopcode")
AML_CREATE_QWORD_FIELD_OP
******************************************************************************/
+
/*
* Master Opcode information table. A summary of everything we know about each
* opcode, all in one place.
@@ -515,9 +520,10 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
AML_TYPE_NAMED_FIELD,
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
/* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP,
- ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+ ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT,
AML_TYPE_NAMED_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD |
+ AML_DEFER),
/* Internal opcodes that map to invalid AML opcodes */
@@ -619,9 +625,9 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
/* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP,
ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ AML_NSNODE | AML_NAMED | AML_DEFER),
/* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
AML_TYPE_NAMED_NO_OBJ,
@@ -779,3 +785,25 @@ char *acpi_ps_get_opcode_name(u16 opcode)
#endif
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_argument_count
+ *
+ * PARAMETERS: op_type - Type associated with the AML opcode
+ *
+ * RETURN: Argument count
+ *
+ * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
+ *
+ ******************************************************************************/
+
+u8 acpi_ps_get_argument_count(u32 op_type)
+{
+
+ if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
+ return (acpi_gbl_argument_count[op_type]);
+ }
+
+ return (0);
+}
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index 5d63f48e56b5..15e1702e48d6 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,6 +205,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|| (op->common.parent->common.aml_opcode ==
AML_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)
+ || (op->common.parent->common.aml_opcode ==
AML_VAR_PACKAGE_OP)) {
replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
@@ -349,19 +351,13 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
parser_state->aml = walk_state->aml_last_while;
walk_state->control_state->common.value = FALSE;
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_BREAK;
- }
+ status = AE_CTRL_BREAK;
break;
case AE_CTRL_CONTINUE:
parser_state->aml = walk_state->aml_last_while;
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_CONTINUE;
- }
+ status = AE_CTRL_CONTINUE;
break;
case AE_CTRL_PENDING:
@@ -383,10 +379,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
* Just close out this package
*/
parser_state->aml = acpi_ps_get_next_package_end(parser_state);
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_PENDING;
- }
+ status = AE_CTRL_PENDING;
break;
case AE_CTRL_FALSE:
@@ -541,7 +534,7 @@ 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",
+ "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
walk_state->method_node->name.
ascii));
@@ -601,6 +594,30 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
* The object is deleted
*/
if (!previous_walk_state->return_desc) {
+ /*
+ * In slack mode execution, if there is no return value
+ * we should implicitly return zero (0) as a default value.
+ */
+ if (acpi_gbl_enable_interpreter_slack &&
+ !previous_walk_state->
+ implicit_return_obj) {
+ previous_walk_state->
+ implicit_return_obj =
+ acpi_ut_create_internal_object
+ (ACPI_TYPE_INTEGER);
+ if (!previous_walk_state->
+ implicit_return_obj) {
+ return_ACPI_STATUS
+ (AE_NO_MEMORY);
+ }
+
+ previous_walk_state->
+ implicit_return_obj->
+ integer.value = 0;
+ }
+
+ /* Restart the calling control method */
+
status =
acpi_ds_restart_control_method
(walk_state,
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index 77cfa4ed0cfe..ee50e67c9443 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 966e7ea2a0c4..1dd355ddd182 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -171,6 +171,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
while (arg) {
arg->common.parent = op;
arg = arg->common.next;
+
+ op->common.arg_list_length++;
}
}
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index 8ca52002db55..7cf1f65cd5bb 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 49f9757434e4..8b86ad5a3201 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 94103bced75e..52581454c47c 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 76bf6d90c700..81e4f081a4ae 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -93,6 +93,7 @@ struct acpi_power_resource {
static struct list_head acpi_power_resource_list;
static const struct file_operations acpi_power_fops = {
+ .owner = THIS_MODULE,
.open = acpi_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -121,7 +122,7 @@ acpi_power_get_context(acpi_handle handle,
}
*resource = acpi_driver_data(device);
- if (!resource)
+ if (!*resource)
return -ENODEV;
return 0;
@@ -543,15 +544,11 @@ static int acpi_power_add_fs(struct acpi_device *device)
}
/* 'status' [R] */
- entry = create_proc_entry(ACPI_POWER_FILE_STATUS,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_POWER_FILE_STATUS,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_power_fops, acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_power_fops;
- entry->data = acpi_driver_data(device);
- }
-
return 0;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a825b431b64f..386e5aa48834 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -112,6 +112,7 @@ static struct acpi_driver acpi_processor_driver = {
#define UNINSTALL_NOTIFY_HANDLER 2
static const struct file_operations acpi_processor_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -326,40 +327,30 @@ static int acpi_processor_add_fs(struct acpi_device *device)
acpi_device_dir(device)->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_processor_info_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'throttling' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_throttling_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_throttling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'limit' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_limit_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_limit_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
@@ -612,6 +603,15 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
request_region(pr->throttling.address, 6, "ACPI CPU throttle");
}
+ /*
+ * If ACPI describes a slot number for this CPU, we can use it
+ * ensure we get the right value in the "physical id" field
+ * of /proc/cpuinfo
+ */
+ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
+ if (ACPI_SUCCESS(status))
+ arch_fix_phys_package_id(pr->id, object.integer.value);
+
return 0;
}
@@ -674,22 +674,21 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
result = PTR_ERR(pr->cdev);
goto end;
}
- if (pr->cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev.bus_id, pr->cdev->id);
-
- result = sysfs_create_link(&device->dev.kobj,
- &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
- result = sysfs_create_link(&pr->cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- return result;
- }
+
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports",
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 0d90ff5fd117..2dd2c1f3a01c 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -847,6 +847,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
/* all processors need to support C1 */
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
pr->power.states[ACPI_STATE_C1].valid = 1;
+ pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT;
}
/* the C0 state only exists as a filler in our array */
pr->power.states[ACPI_STATE_C0].valid = 1;
@@ -959,6 +960,9 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
cx.address);
}
+ if (cx.type == ACPI_STATE_C1) {
+ cx.valid = 1;
+ }
obj = &(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
@@ -1282,6 +1286,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file)
}
static const struct file_operations acpi_processor_power_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -1294,6 +1299,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int result = 0;
+ if (boot_option_idle_override)
+ return 0;
if (!pr)
return -EINVAL;
@@ -1733,6 +1740,9 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int ret;
+ if (boot_option_idle_override)
+ return 0;
+
if (!pr)
return -EINVAL;
@@ -1763,6 +1773,8 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct proc_dir_entry *entry = NULL;
unsigned int i;
+ if (boot_option_idle_override)
+ return 0;
if (!first_run) {
dmi_check_system(processor_power_dmi_table);
@@ -1798,7 +1810,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
* Note that we use previously set idle handler will be used on
* platforms that only support C1.
*/
- if ((pr->flags.power) && (!boot_option_idle_override)) {
+ if (pr->flags.power) {
#ifdef CONFIG_CPU_IDLE
acpi_processor_setup_cpuidle(pr);
pr->power.dev.cpu = pr->id;
@@ -1822,24 +1834,23 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
}
/* 'power' [R] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_processor_power_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_power_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
+ if (boot_option_idle_override)
+ return 0;
+
#ifdef CONFIG_CPU_IDLE
- if ((pr->flags.power) && (!boot_option_idle_override))
+ if (pr->flags.power)
cpuidle_unregister_device(&pr->power.dev);
#endif
pr->flags.power_setup_done = 0;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index b477a4be8a69..d80b2d1441af 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -411,6 +411,7 @@ EXPORT_SYMBOL(acpi_processor_notify_smm);
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_processor_perf_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_perf_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -456,7 +457,6 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
static void acpi_cpufreq_add_file(struct acpi_processor *pr)
{
- struct proc_dir_entry *entry = NULL;
struct acpi_device *device = NULL;
@@ -464,14 +464,9 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr)
return;
/* add file 'performance' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
- S_IFREG | S_IRUGO,
- acpi_device_dir(device));
- if (entry){
- entry->proc_fops = &acpi_processor_perf_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO,
+ acpi_device_dir(device),
+ &acpi_processor_perf_fops, acpi_driver_data(device));
return;
}
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 649ae99b9216..ef34b18f95ca 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -509,6 +509,7 @@ static ssize_t acpi_processor_write_limit(struct file * file,
}
struct file_operations acpi_processor_limit_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_limit_open_fs,
.read = seq_read,
.write = acpi_processor_write_limit,
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 0bba3a914e86..bb06738860c4 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -1252,6 +1252,7 @@ static ssize_t acpi_processor_write_throttling(struct file *file,
}
struct file_operations acpi_processor_throttling_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_throttling_open_fs,
.read = seq_read,
.write = acpi_processor_write_throttling,
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 271e61509eeb..7f96332822bf 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 0dd2ce8a3475..8a112d11d491 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,7 @@ acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length);
static u8 acpi_rs_count_set_bits(u16 bit_field)
{
- u8 bits_set;
+ acpi_native_uint bits_set;
ACPI_FUNCTION_ENTRY();
@@ -81,10 +81,10 @@ static u8 acpi_rs_count_set_bits(u16 bit_field)
/* Zero the least significant bit that is set */
- bit_field &= (bit_field - 1);
+ bit_field &= (u16) (bit_field - 1);
}
- return (bits_set);
+ return ((u8) bits_set);
}
/*******************************************************************************
@@ -211,6 +211,24 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
* variable-length fields
*/
switch (resource->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+
+ /* Length can be 3 or 2 */
+
+ if (resource->data.irq.descriptor_length == 2) {
+ total_size--;
+ }
+ break;
+
+ case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+
+ /* Length can be 1 or 0 */
+
+ if (resource->data.irq.descriptor_length == 0) {
+ total_size--;
+ }
+ break;
+
case ACPI_RESOURCE_TYPE_VENDOR:
/*
* Vendor Defined Resource:
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 50da494c3ee2..faddaee1bc07 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 46da116a4030..6bbbb7b8941a 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,8 +87,10 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
*
******************************************************************************/
-struct acpi_rsdump_info acpi_rs_dump_irq[6] = {
+struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
+ "Descriptor Length", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
acpi_gbl_he_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
@@ -115,9 +117,11 @@ struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
NULL}
};
-struct acpi_rsdump_info acpi_rs_dump_start_dpf[3] = {
+struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
"Start-Dependent-Functions", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
+ "Descriptor Length", NULL},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
"Compatibility Priority", acpi_gbl_config_decode},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 2c2adb6292c1..3f0a1fedbe0e 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 b297bc3e4419..b66d42e7402e 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -185,7 +185,7 @@ struct acpi_rsconvert_info acpi_rs_convert_end_tag[2] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
+struct acpi_rsconvert_info acpi_rs_get_start_dpf[6] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT,
ACPI_RS_SIZE(struct acpi_resource_start_dependent),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_start_dpf)},
@@ -196,6 +196,12 @@ struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
ACPI_ACCEPTABLE_CONFIGURATION,
2},
+ /* Get the descriptor length (0 or 1 for Start Dpf descriptor) */
+
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ AML_OFFSET(start_dpf.descriptor_type),
+ 0},
+
/* All done if there is no flag byte present in the descriptor */
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1},
@@ -219,7 +225,9 @@ struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = {
+struct acpi_rsconvert_info acpi_rs_set_start_dpf[10] = {
+ /* Start with a default descriptor of length 1 */
+
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT,
sizeof(struct aml_resource_start_dependent),
ACPI_RSC_TABLE_SIZE(acpi_rs_set_start_dpf)},
@@ -236,6 +244,33 @@ struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = {
AML_OFFSET(start_dpf.flags),
2},
/*
+ * All done if the output descriptor length is required to be 1
+ * (i.e., optimization to 0 bytes cannot be attempted)
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ 1},
+
+ /* Set length to 0 bytes (no flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0,
+ sizeof(struct aml_resource_start_dependent_noprio)},
+
+ /*
+ * All done if the output descriptor length is required to be 0.
+ *
+ * TBD: Perhaps we should check for error if input flags are not
+ * compatible with a 0-byte descriptor.
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ 0},
+
+ /* Reset length to 1 byte (descriptor with flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_start_dependent)},
+
+ /*
* All done if flags byte is necessary -- if either priority value
* is not ACPI_ACCEPTABLE_CONFIGURATION
*/
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 5657f7b95039..a8805efc0366 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,7 @@ ACPI_MODULE_NAME("rsirq")
* acpi_rs_get_irq
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
+struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ,
ACPI_RS_SIZE(struct acpi_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)},
@@ -69,6 +69,12 @@ struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
ACPI_EDGE_SENSITIVE,
1},
+ /* Get the descriptor length (2 or 3 for IRQ descriptor) */
+
+ {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.irq.descriptor_length),
+ AML_OFFSET(irq.descriptor_type),
+ 0},
+
/* All done if no flag byte present in descriptor */
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3},
@@ -94,7 +100,9 @@ struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
+struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
+ /* Start with a default descriptor of length 3 */
+
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ,
sizeof(struct aml_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)},
@@ -105,7 +113,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
AML_OFFSET(irq.irq_mask),
ACPI_RS_OFFSET(data.irq.interrupt_count)},
- /* Set the flags byte by default */
+ /* Set the flags byte */
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
AML_OFFSET(irq.flags),
@@ -118,6 +126,33 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable),
AML_OFFSET(irq.flags),
4},
+
+ /*
+ * All done if the output descriptor length is required to be 3
+ * (i.e., optimization to 2 bytes cannot be attempted)
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.irq.descriptor_length),
+ 3},
+
+ /* Set length to 2 bytes (no flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)},
+
+ /*
+ * All done if the output descriptor length is required to be 2.
+ *
+ * TBD: Perhaps we should check for error if input flags are not
+ * compatible with a 2-byte descriptor.
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.irq.descriptor_length),
+ 2},
+
+ /* Reset length to 3 bytes (descriptor with flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)},
+
/*
* Check if the flags byte is necessary. Not needed if the flags are:
* ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE
@@ -134,7 +169,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
ACPI_RS_OFFSET(data.irq.sharable),
ACPI_EXCLUSIVE},
- /* irq_no_flags() descriptor can be used */
+ /* We can optimize to a 2-byte irq_no_flags() descriptor */
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)}
};
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index ca21e4660c79..b78c7e797a19 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 521eab7dd8df..63b21abd90bb 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 c7081afa893a..de1ac3881b22 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -497,6 +497,17 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
}
break;
+ case ACPI_RSC_EXIT_EQ:
+ /*
+ * Control - Exit conversion if equal
+ */
+ if (*ACPI_ADD_PTR(u8, resource,
+ COMPARE_TARGET(info)) ==
+ COMPARE_VALUE(info)) {
+ goto exit;
+ }
+ break;
+
default:
ACPI_ERROR((AE_INFO, "Invalid conversion opcode"));
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index 11c0bd7b9cfd..befe2302f41b 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,17 +97,17 @@ u8 acpi_rs_decode_bitmask(u16 mask, u8 * list)
u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
{
acpi_native_uint i;
- u16 mask;
+ acpi_native_uint mask;
ACPI_FUNCTION_ENTRY();
/* Encode the list into a single bitmask */
for (i = 0, mask = 0; i < count; i++) {
- mask |= (0x0001 << list[i]);
+ mask |= (0x1 << list[i]);
}
- return (mask);
+ return ((u16) mask);
}
/*******************************************************************************
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 4c3fd4cdaf73..f59f4c4e034c 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 585ae3c9c8ea..10a36512647c 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -483,8 +483,6 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
struct file_operations *state_fops,
struct file_operations *alarm_fops, void *data)
{
- struct proc_dir_entry *entry = NULL;
-
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
@@ -494,34 +492,19 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
}
/* 'info' [R] */
- if (info_fops) {
- entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
- if (entry) {
- entry->proc_fops = info_fops;
- entry->data = data;
- entry->owner = THIS_MODULE;
- }
- }
+ if (info_fops)
+ proc_create_data(ACPI_SBS_FILE_INFO, S_IRUGO, *dir,
+ info_fops, data);
/* 'state' [R] */
- if (state_fops) {
- entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
- if (entry) {
- entry->proc_fops = state_fops;
- entry->data = data;
- entry->owner = THIS_MODULE;
- }
- }
+ if (state_fops)
+ proc_create_data(ACPI_SBS_FILE_STATE, S_IRUGO, *dir,
+ state_fops, data);
/* 'alarm' [R/W] */
- if (alarm_fops) {
- entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
- if (entry) {
- entry->proc_fops = alarm_fops;
- entry->data = data;
- entry->owner = THIS_MODULE;
- }
- }
+ if (alarm_fops)
+ proc_create_data(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir,
+ alarm_fops, data);
return 0;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e6ce262b5d44..6d85289f1c12 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -677,9 +677,8 @@ acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
device->wakeup.resources.count = package->package.count - 2;
for (i = 0; i < device->wakeup.resources.count; i++) {
element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
return AE_BAD_DATA;
- }
device->wakeup.resources.handles[i] = element->reference.handle;
}
@@ -692,6 +691,9 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
+ union acpi_object in_arg[3];
+ struct acpi_object_list arg_list = { 3, in_arg };
+ acpi_status psw_status = AE_OK;
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
@@ -700,7 +702,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{"", 0},
};
-
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -718,6 +719,45 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ /* Call _PSW/_DSW object to disable its ability to wake the sleeping
+ * system for the ACPI device with the _PRW object.
+ * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+ * So it is necessary to call _DSW object first. Only when it is not
+ * present will the _PSW object used.
+ */
+ /*
+ * Three agruments are needed for the _DSW object.
+ * Argument 0: enable/disable the wake capabilities
+ * When _DSW object is called to disable the wake capabilities, maybe
+ * the first argument is filled. The value of the other two agruments
+ * is meaningless.
+ */
+ in_arg[0].type = ACPI_TYPE_INTEGER;
+ in_arg[0].integer.value = 0;
+ in_arg[1].type = ACPI_TYPE_INTEGER;
+ in_arg[1].integer.value = 0;
+ in_arg[2].type = ACPI_TYPE_INTEGER;
+ in_arg[2].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_DSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
+ /*
+ * When the _DSW object is not present, OSPM will call _PSW object.
+ */
+ if (psw_status == AE_NOT_FOUND) {
+ /*
+ * Only one agruments is required for the _PSW object.
+ * agrument 0: enable/disable the wake capabilities
+ */
+ arg_list.count = 1;
+ in_arg[0].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_PSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
+ "evaluate _PSW\n"));
+ }
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
@@ -882,10 +922,7 @@ 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;
-
+ acpi_handle h_dummy;
if (!device)
return -EINVAL;
@@ -895,18 +932,18 @@ acpi_video_bus_match(struct acpi_device *device)
*/
/* 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)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
return 0;
/* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
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)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
return 0;
return -ENODEV;
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 71183eea7906..c3b0cd88d09f 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -51,7 +51,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
}
#ifdef CONFIG_SUSPEND
-static struct platform_suspend_ops acpi_pm_ops;
+static struct platform_suspend_ops acpi_suspend_ops;
extern void do_suspend_lowlevel(void);
@@ -65,11 +65,11 @@ static u32 acpi_suspend_states[] = {
static int init_8259A_after_S1;
/**
- * acpi_pm_begin - Set the target system sleep state to the state
+ * acpi_suspend_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported.
*/
-static int acpi_pm_begin(suspend_state_t pm_state)
+static int acpi_suspend_begin(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
@@ -85,13 +85,13 @@ static int acpi_pm_begin(suspend_state_t pm_state)
}
/**
- * acpi_pm_prepare - Do preliminary suspend work.
+ * acpi_suspend_prepare - Do preliminary suspend work.
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
-static int acpi_pm_prepare(void)
+static int acpi_suspend_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
@@ -104,7 +104,7 @@ static int acpi_pm_prepare(void)
}
/**
- * acpi_pm_enter - Actually enter a sleep state.
+ * acpi_suspend_enter - Actually enter a sleep state.
* @pm_state: ignored
*
* Flush caches and go to sleep. For STR we have to call arch-specific
@@ -112,7 +112,7 @@ static int acpi_pm_prepare(void)
* It's unfortunate, but it works. Please fix if you're feeling frisky.
*/
-static int acpi_pm_enter(suspend_state_t pm_state)
+static int acpi_suspend_enter(suspend_state_t pm_state)
{
acpi_status status = AE_OK;
unsigned long flags = 0;
@@ -169,13 +169,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
}
/**
- * acpi_pm_finish - Instruct the platform to leave a sleep state.
+ * acpi_suspend_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
-static void acpi_pm_finish(void)
+static void acpi_suspend_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
@@ -196,19 +196,19 @@ static void acpi_pm_finish(void)
}
/**
- * acpi_pm_end - Finish up suspend sequence.
+ * acpi_suspend_end - Finish up suspend sequence.
*/
-static void acpi_pm_end(void)
+static void acpi_suspend_end(void)
{
/*
- * This is necessary in case acpi_pm_finish() is not called during a
+ * This is necessary in case acpi_suspend_finish() is not called during a
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
}
-static int acpi_pm_state_valid(suspend_state_t pm_state)
+static int acpi_suspend_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -224,13 +224,13 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
}
}
-static struct platform_suspend_ops acpi_pm_ops = {
- .valid = acpi_pm_state_valid,
- .begin = acpi_pm_begin,
- .prepare = acpi_pm_prepare,
- .enter = acpi_pm_enter,
- .finish = acpi_pm_finish,
- .end = acpi_pm_end,
+static struct platform_suspend_ops acpi_suspend_ops = {
+ .valid = acpi_suspend_state_valid,
+ .begin = acpi_suspend_begin,
+ .prepare = acpi_suspend_prepare,
+ .enter = acpi_suspend_enter,
+ .finish = acpi_suspend_finish,
+ .end = acpi_suspend_end,
};
/*
@@ -492,7 +492,7 @@ int __init acpi_sleep_init(void)
}
}
- suspend_set_ops(&acpi_pm_ops);
+ suspend_set_ops(&acpi_suspend_ops);
#endif
#ifdef CONFIG_HIBERNATION
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index f8df5217d477..8a5fe8710513 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -440,6 +440,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
}
static const struct file_operations acpi_system_wakeup_device_fops = {
+ .owner = THIS_MODULE,
.open = acpi_system_wakeup_device_open_fs,
.read = seq_read,
.write = acpi_system_write_wakeup_device,
@@ -449,6 +450,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = {
#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_system_sleep_fops = {
+ .owner = THIS_MODULE,
.open = acpi_system_sleep_open_fs,
.read = seq_read,
.write = acpi_system_write_sleep,
@@ -459,6 +461,7 @@ static const struct file_operations acpi_system_sleep_fops = {
#ifdef HAVE_ACPI_LEGACY_ALARM
static const struct file_operations acpi_system_alarm_fops = {
+ .owner = THIS_MODULE,
.open = acpi_system_alarm_open_fs,
.read = seq_read,
.write = acpi_system_write_alarm,
@@ -477,37 +480,26 @@ static u32 rtc_handler(void *context)
static int __init acpi_sleep_proc_init(void)
{
- struct proc_dir_entry *entry = NULL;
-
if (acpi_disabled)
return 0;
#ifdef CONFIG_ACPI_PROCFS
/* 'sleep' [R/W] */
- entry =
- create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_sleep_fops;
+ proc_create("sleep", S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_sleep_fops);
#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
/* 'alarm' [R/W] */
- entry =
- create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_alarm_fops;
+ proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_alarm_fops);
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
#endif /* HAVE_ACPI_LEGACY_ALARM */
/* 'wakeup device' [R/W] */
- entry =
- create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_wakeup_device_fops;
+ proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_wakeup_device_fops);
return 0;
}
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 4749f379a915..769f24855eb6 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -396,6 +396,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file)
}
static const struct file_operations acpi_system_info_ops = {
+ .owner = THIS_MODULE,
.open = acpi_system_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -406,6 +407,7 @@ static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
static const struct file_operations acpi_system_dsdt_ops = {
+ .owner = THIS_MODULE,
.read = acpi_system_read_dsdt,
};
@@ -430,6 +432,7 @@ static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t,
loff_t *);
static const struct file_operations acpi_system_fadt_ops = {
+ .owner = THIS_MODULE,
.read = acpi_system_read_fadt,
};
@@ -454,31 +457,23 @@ static int acpi_system_procfs_init(void)
{
struct proc_dir_entry *entry;
int error = 0;
- char *name;
/* 'info' [R] */
- name = ACPI_SYSTEM_FILE_INFO;
- entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
+ entry = proc_create(ACPI_SYSTEM_FILE_INFO, S_IRUGO, acpi_root_dir,
+ &acpi_system_info_ops);
if (!entry)
goto Error;
- else {
- entry->proc_fops = &acpi_system_info_ops;
- }
/* 'dsdt' [R] */
- name = ACPI_SYSTEM_FILE_DSDT;
- entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_dsdt_ops;
- else
+ entry = proc_create(ACPI_SYSTEM_FILE_DSDT, S_IRUSR, acpi_root_dir,
+ &acpi_system_dsdt_ops);
+ if (!entry)
goto Error;
/* 'fadt' [R] */
- name = ACPI_SYSTEM_FILE_FADT;
- entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_fadt_ops;
- else
+ entry = proc_create(ACPI_SYSTEM_FILE_FADT, S_IRUSR, acpi_root_dir,
+ &acpi_system_fadt_ops);
+ if (!entry)
goto Error;
Done:
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 002bb33003af..949d4114eb9f 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
index 058c064948e1..9ca3afc98c80 100644
--- a/drivers/acpi/tables/tbfind.c
+++ b/drivers/acpi/tables/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,12 +70,22 @@ acpi_tb_find_table(char *signature,
{
acpi_native_uint i;
acpi_status status;
+ struct acpi_table_header header;
ACPI_FUNCTION_TRACE(tb_find_table);
+ /* Normalize the input strings */
+
+ ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header));
+ ACPI_STRNCPY(header.signature, signature, ACPI_NAME_SIZE);
+ ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE);
+ ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+
+ /* Search for the 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)) {
+ header.signature, ACPI_NAME_SIZE)) {
/* Not the requested table */
@@ -104,20 +114,24 @@ acpi_tb_find_table(char *signature,
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))
+ header.signature, ACPI_NAME_SIZE) && (!oem_id[0]
+ ||
+ !ACPI_MEMCMP
+ (acpi_gbl_root_table_list.
+ tables[i].pointer->
+ oem_id,
+ header.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,
+ pointer->oem_table_id,
+ header.oem_table_id,
ACPI_OEM_TABLE_ID_SIZE))) {
*table_index = i;
ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Found table [%4.4s]\n", signature));
+ "Found table [%4.4s]\n",
+ header.signature));
return_ACPI_STATUS(AE_OK);
}
}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 3bc0c67a9283..402f93e1ff20 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,13 +125,20 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc,
/* The table must be either an SSDT or a PSDT or an OEMx */
- if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
- &&
- (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
- && (strncmp(table_desc->pointer->signature, "OEM", 3))) {
- ACPI_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s], must be SSDT, PSDT or OEMx",
- table_desc->pointer->signature));
+ if (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)&&
+ !ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)&&
+ strncmp(table_desc->pointer->signature, "OEM", 3)) {
+ /* Check for a printable name */
+ if (acpi_ut_valid_acpi_name(
+ *(u32 *) table_desc->pointer->signature)) {
+ ACPI_ERROR((AE_INFO, "Table has invalid signature "
+ "[%4.4s], must be SSDT or PSDT",
+ table_desc->pointer->signature));
+ } else {
+ ACPI_ERROR((AE_INFO, "Table has invalid signature "
+ "(0x%8.8X), must be SSDT or PSDT",
+ *(u32 *) table_desc->pointer->signature));
+ }
return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
@@ -162,6 +169,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc,
acpi_tb_delete_table(table_desc);
*table_index = i;
+ status = AE_ALREADY_EXISTS;
goto release;
}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 010f19652f80..bc019b9b6a68 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -212,7 +212,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
if (checksum) {
ACPI_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
+ "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
table->signature, table->checksum,
(u8) (table->checksum - checksum)));
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index a9e3331fee5d..fb57b93c2495 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -635,6 +635,95 @@ acpi_status acpi_load_tables(void)
ACPI_EXPORT_SYMBOL(acpi_load_tables)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_table_handler
+ *
+ * PARAMETERS: Handler - Table event handler
+ * Context - Value passed to the handler on each event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install table event handler
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_table_handler(acpi_tbl_handler handler, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_table_handler);
+
+ if (!handler) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow more than one handler */
+
+ if (acpi_gbl_table_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ /* Install the handler */
+
+ acpi_gbl_table_handler = handler;
+ acpi_gbl_table_handler_context = context;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_table_handler)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_table_handler
+ *
+ * PARAMETERS: Handler - Table event handler that was installed
+ * previously.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove table event handler
+ *
+ ******************************************************************************/
+acpi_status acpi_remove_table_handler(acpi_tbl_handler handler)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_remove_table_handler);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Make sure that the installed handler is the same */
+
+ if (!handler || handler != acpi_gbl_table_handler) {
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Remove the handler */
+
+ acpi_gbl_table_handler = NULL;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_table_handler)
+
+
static int __init acpi_no_auto_ssdt_setup(char *s) {
printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index 9ecb4b6c1e7d..b8c0dfa084f6 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 766bd25d3376..504385b1f211 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -198,6 +198,7 @@ struct acpi_thermal {
};
static const struct file_operations acpi_thermal_state_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -205,6 +206,7 @@ static const struct file_operations acpi_thermal_state_fops = {
};
static const struct file_operations acpi_thermal_temp_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_temp_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -212,6 +214,7 @@ static const struct file_operations acpi_thermal_temp_fops = {
};
static const struct file_operations acpi_thermal_trip_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_trip_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -219,6 +222,7 @@ static const struct file_operations acpi_thermal_trip_fops = {
};
static const struct file_operations acpi_thermal_cooling_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_cooling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_cooling_mode,
@@ -227,6 +231,7 @@ static const struct file_operations acpi_thermal_cooling_fops = {
};
static const struct file_operations acpi_thermal_polling_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_polling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_polling,
@@ -884,10 +889,15 @@ static void acpi_thermal_check(void *data)
static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
+ int result;
if (!tz)
return -EINVAL;
+ result = acpi_thermal_get_temperature(tz);
+ if (result)
+ return result;
+
return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
}
@@ -1012,6 +1022,18 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
return -EINVAL;
}
+static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temperature) {
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (tz->trips.critical.flags.valid) {
+ *temperature = KELVIN_TO_MILLICELSIUS(
+ tz->trips.critical.temperature);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1103,6 +1125,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.set_mode = thermal_set_mode,
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
+ .get_crit_temp = thermal_get_crit_temp,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
@@ -1123,7 +1146,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
- tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+ tz->thermal_zone = thermal_zone_device_register("acpitz",
trips, tz, &acpi_thermal_zone_ops);
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
@@ -1419,63 +1442,47 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
}
/* 'state' [R] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_thermal_state_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'temperature' [R] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_thermal_temp_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_temp_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'trip_points' [R] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
- S_IRUGO,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
+ S_IRUGO,
+ acpi_device_dir(device),
+ &acpi_thermal_trip_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_trip_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'cooling_mode' [R/W] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_thermal_cooling_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_cooling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'polling_frequency' [R/W] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_thermal_polling_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_polling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 6e56d5f7c43a..ede084829a70 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,7 @@ acpi_status acpi_ut_delete_caches(void)
if (acpi_gbl_display_final_mem_stats) {
ACPI_STRCPY(buffer, "MEMORY");
- acpi_db_display_statistics(buffer);
+ (void)acpi_db_display_statistics(buffer);
}
#endif
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 285a0f531760..245fa80cf600 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 879eaa10d3ae..655c290aca7b 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,8 @@
#include <acpi/acpi.h>
#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utcopy")
@@ -172,22 +174,21 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
case ACPI_TYPE_LOCAL_REFERENCE:
- /*
- * This is an object reference. Attempt to dereference it.
- */
+ /* This is an object reference. */
+
switch (internal_object->reference.opcode) {
case AML_INT_NAMEPATH_OP:
/* For namepath, return the object handle ("reference") */
default:
- /*
- * Use the object type of "Any" to indicate a reference
- * to object containing a handle to an ACPI named object.
- */
- external_object->type = ACPI_TYPE_ANY;
+
+ /* We are referring to the namespace node */
+
external_object->reference.handle =
internal_object->reference.node;
+ external_object->reference.actual_type =
+ acpi_ns_get_type(internal_object->reference.node);
break;
}
break;
@@ -215,6 +216,11 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
/*
* There is no corresponding external object type
*/
+ ACPI_ERROR((AE_INFO,
+ "Unsupported object type, cannot convert to external object: %s",
+ acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE
+ (internal_object))));
+
return_ACPI_STATUS(AE_SUPPORT);
}
@@ -455,6 +461,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_LOCAL_REFERENCE:
internal_object = acpi_ut_create_internal_object((u8)
external_object->
@@ -464,9 +471,18 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
}
break;
+ case ACPI_TYPE_ANY: /* This is the case for a NULL object */
+
+ *ret_internal_object = NULL;
+ return_ACPI_STATUS(AE_OK);
+
default:
/* All other types are not supported */
+ ACPI_ERROR((AE_INFO,
+ "Unsupported object type, cannot convert to internal object: %s",
+ acpi_ut_get_type_name(external_object->type)));
+
return_ACPI_STATUS(AE_SUPPORT);
}
@@ -502,6 +518,10 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
external_object->buffer.length);
internal_object->buffer.length = external_object->buffer.length;
+
+ /* Mark buffer data valid */
+
+ internal_object->buffer.flags |= AOPOBJ_DATA_VALID;
break;
case ACPI_TYPE_INTEGER:
@@ -509,6 +529,15 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
internal_object->integer.value = external_object->integer.value;
break;
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ /* TBD: should validate incoming handle */
+
+ internal_object->reference.opcode = AML_INT_NAMEPATH_OP;
+ internal_object->reference.node =
+ external_object->reference.handle;
+ break;
+
default:
/* Other types can't get here */
break;
@@ -570,13 +599,17 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object,
/* Truncate package and delete it */
- package_object->package.count = i;
+ package_object->package.count = (u32) i;
package_elements[i] = NULL;
acpi_ut_remove_reference(package_object);
return_ACPI_STATUS(status);
}
}
+ /* Mark package data valid */
+
+ package_object->package.flags |= AOPOBJ_DATA_VALID;
+
*internal_object = package_object;
return_ACPI_STATUS(status);
}
@@ -709,7 +742,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
/*
* We copied the reference object, so we now must add a reference
* to the object pointed to by the reference
+ *
+ * DDBHandle reference (from Load/load_table is a special reference,
+ * it's Reference.Object is the table index, so does not need to
+ * increase the reference count
*/
+ if (source_desc->reference.opcode == AML_LOAD_OP) {
+ break;
+ }
+
acpi_ut_add_reference(source_desc->reference.object);
break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 7361204b1eef..f938f465efa4 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -68,9 +68,9 @@ static const char *acpi_ut_trim_function_name(const char *function_name);
void acpi_ut_init_stack_ptr_trace(void)
{
- u32 current_sp;
+ acpi_size current_sp;
- acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF(&current_sp, NULL);
+ acpi_gbl_entry_stack_pointer = &current_sp;
}
/*******************************************************************************
@@ -89,10 +89,8 @@ void acpi_ut_track_stack_ptr(void)
{
acpi_size current_sp;
- current_sp = ACPI_PTR_DIFF(&current_sp, NULL);
-
- if (current_sp < acpi_gbl_lowest_stack_pointer) {
- acpi_gbl_lowest_stack_pointer = current_sp;
+ if (&current_sp < acpi_gbl_lowest_stack_pointer) {
+ acpi_gbl_lowest_stack_pointer = &current_sp;
}
if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) {
@@ -203,6 +201,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
va_start(args, format);
acpi_os_vprintf(format, args);
+ va_end(args);
}
ACPI_EXPORT_SYMBOL(acpi_ut_debug_print)
@@ -240,6 +239,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level,
va_start(args, format);
acpi_os_vprintf(format, args);
+ va_end(args);
}
ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw)
@@ -524,6 +524,11 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
u32 temp32;
u8 buf_char;
+ if (!buffer) {
+ acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
+ return;
+ }
+
if ((count < 4) || (count & 0x01)) {
display = DB_BYTE_DISPLAY;
}
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index f777cebdc46d..1fbc35139e84 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,7 +158,7 @@ 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_gbl_global_lock_mutex) {
+ if (object == acpi_gbl_global_lock_mutex) {
/* Global Lock has extra semaphore */
@@ -252,6 +252,17 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
}
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
+ "***** Bank Field %p\n", object));
+
+ second_desc = acpi_ns_get_secondary_object(object);
+ if (second_desc) {
+ acpi_ut_delete_object_desc(second_desc);
+ }
+ break;
+
default:
break;
}
@@ -524,10 +535,12 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_LOCAL_REFERENCE:
/*
- * The target of an Index (a package, string, or buffer) must track
- * changes to the ref count of the index.
+ * The target of an Index (a package, string, or buffer) or a named
+ * reference must track changes to the ref count of the index or
+ * target object.
*/
- if (object->reference.opcode == AML_INDEX_OP) {
+ if ((object->reference.opcode == AML_INDEX_OP) ||
+ (object->reference.opcode == AML_INT_NAMEPATH_OP)) {
next_object = object->reference.object;
}
break;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 0042b7e78b26..05e61be267d5 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 630c9a2c5b7b..a6e71b801d2d 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -602,6 +602,48 @@ char *acpi_ut_get_mutex_name(u32 mutex_id)
return (acpi_gbl_mutex_names[mutex_id]);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_notify_name
+ *
+ * PARAMETERS: notify_value - Value from the Notify() request
+ *
+ * RETURN: String corresponding to the Notify Value.
+ *
+ * DESCRIPTION: Translate a Notify Value to a notify namestring.
+ *
+ ******************************************************************************/
+
+/* Names for Notify() values, used for debug output */
+
+static const char *acpi_gbl_notify_value_names[] = {
+ "Bus Check",
+ "Device Check",
+ "Device Wake",
+ "Eject Request",
+ "Device Check Light",
+ "Frequency Mismatch",
+ "Bus Mode Mismatch",
+ "Power Fault",
+ "Capabilities Check",
+ "Device PLD Check",
+ "Reserved",
+ "System Locality Update"
+};
+
+const char *acpi_ut_get_notify_name(u32 notify_value)
+{
+
+ if (notify_value <= ACPI_NOTIFY_MAX) {
+ return (acpi_gbl_notify_value_names[notify_value]);
+ } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+ return ("Reserved");
+ } else { /* Greater or equal to 0x80 */
+
+ return ("**Device Specific**");
+ }
+}
#endif
/*******************************************************************************
@@ -675,12 +717,13 @@ void acpi_ut_init_globals(void)
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
- /* Global notify handlers */
+ /* Global handlers */
acpi_gbl_system_notify.handler = NULL;
acpi_gbl_device_notify.handler = NULL;
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
+ acpi_gbl_table_handler = NULL;
/* Global Lock support */
@@ -722,7 +765,7 @@ void acpi_ut_init_globals(void)
acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
#ifdef ACPI_DEBUG_OUTPUT
- acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
+ acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
#endif
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ad3c0d0a5cf8..cae515fc02d3 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,9 +125,12 @@ void acpi_ut_subsystem_shutdown(void)
acpi_gbl_startup_flags = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+#ifndef ACPI_ASL_COMPILER
+
/* Close the acpi_event Handling */
acpi_ev_terminate();
+#endif
/* Close the Namespace */
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 0c56a0d20b29..c927324fdd26 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,7 @@ acpi_ut_short_divide(acpi_integer in_dividend,
*out_quotient = in_dividend / divisor;
}
if (out_remainder) {
- *out_remainder = (u32) in_dividend % divisor;
+ *out_remainder = (u32) (in_dividend % divisor);
}
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 2d19f71e9cfa..e4ba7192cd15 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1033,6 +1033,7 @@ acpi_ut_error(char *module_name, u32 line_number, char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
@@ -1061,6 +1062,8 @@ acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
+ va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
@@ -1077,4 +1080,5 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf("\n");
+ va_end(args);
}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 4820bc86d1f5..f7d602b1a894 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 e08b3fa6639f..e68466de8044 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,6 +107,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name,
switch (type) {
case ACPI_TYPE_REGION:
case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
/* These types require a secondary object */
@@ -469,9 +470,8 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_POWER:
- /*
- * No extra data for these types
- */
+ /* No extra data for these types */
+
break;
case ACPI_TYPE_LOCAL_REFERENCE:
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index b630ee137ee1..c3e3e1308edc 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 edcaafad0a31..63a6d3d77d88 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* 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 2d496918b3cd..f8bdadf3c32f 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxface")
+#ifndef ACPI_ASL_COMPILER
/*******************************************************************************
*
* FUNCTION: acpi_initialize_subsystem
@@ -192,24 +193,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
}
}
- /*
- * Complete the GPE initialization for the GPE blocks defined in the FADT
- * (GPE block 0 and 1).
- *
- * Note1: This is where the _PRW methods are executed for the GPEs. These
- * methods can only be executed after the SCI and Global Lock handlers are
- * installed and initialized.
- *
- * Note2: Currently, there seems to be no need to run the _REG methods
- * before execution of the _PRW methods and enabling of the GPEs.
- */
- if (!(flags & ACPI_NO_EVENT_INIT)) {
- status = acpi_ev_install_fadt_gpes();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- }
-
return_ACPI_STATUS(status);
}
@@ -280,6 +263,23 @@ acpi_status acpi_initialize_objects(u32 flags)
}
/*
+ * Complete the GPE initialization for the GPE blocks defined in the FADT
+ * (GPE block 0 and 1).
+ *
+ * Note1: This is where the _PRW methods are executed for the GPEs. These
+ * methods can only be executed after the SCI and Global Lock handlers are
+ * installed and initialized.
+ *
+ * Note2: Currently, there seems to be no need to run the _REG methods
+ * before execution of the _PRW methods and enabling of the GPEs.
+ */
+ if (!(flags & ACPI_NO_EVENT_INIT)) {
+ status = acpi_ev_install_fadt_gpes();
+ if (ACPI_FAILURE(status))
+ return (status);
+ }
+
+ /*
* Empty the caches (delete the cached objects) on the assumption that
* the table load filled them up more than they will be at runtime --
* thus wasting non-paged memory.
@@ -292,6 +292,7 @@ acpi_status acpi_initialize_objects(u32 flags)
ACPI_EXPORT_SYMBOL(acpi_initialize_objects)
+#endif
/*******************************************************************************
*
* FUNCTION: acpi_terminate
@@ -335,6 +336,7 @@ acpi_status acpi_terminate(void)
}
ACPI_EXPORT_SYMBOL(acpi_terminate)
+#ifndef ACPI_ASL_COMPILER
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -490,3 +492,4 @@ acpi_status acpi_purge_cached_objects(void)
}
ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
+#endif
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 44ea60cf21c0..100926143818 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -398,7 +398,7 @@ acpi_evaluate_reference(acpi_handle handle,
element = &(package->package.elements[i]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
status = AE_BAD_DATA;
printk(KERN_ERR PREFIX
"Expecting a [Reference] package element, found type %X\n",
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 980a74188781..5e5dda3a3027 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -57,8 +57,6 @@
#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
-#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
-#define ACPI_VIDEO_HEAD_END (~0u)
#define MAX_NAME_LEN 20
#define ACPI_VIDEO_DISPLAY_CRT 1
@@ -192,6 +190,7 @@ struct acpi_video_device {
/* bus */
static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -200,6 +199,7 @@ static struct file_operations acpi_video_bus_info_fops = {
static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_ROM_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_ROM_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -209,6 +209,7 @@ static struct file_operations acpi_video_bus_ROM_fops = {
static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_bus_POST_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_POST_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -217,6 +218,7 @@ static struct file_operations acpi_video_bus_POST_info_fops = {
static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_POST_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_POST_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -225,6 +227,7 @@ static struct file_operations acpi_video_bus_POST_fops = {
static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_DOS_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_DOS_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -235,6 +238,7 @@ static struct file_operations acpi_video_bus_DOS_fops = {
static int acpi_video_device_info_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -244,6 +248,7 @@ static struct file_operations acpi_video_device_info_fops = {
static int acpi_video_device_state_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_state_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -253,6 +258,7 @@ static struct file_operations acpi_video_device_state_fops = {
static int acpi_video_device_brightness_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_brightness_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_brightness_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -262,6 +268,7 @@ static struct file_operations acpi_video_device_brightness_fops = {
static int acpi_video_device_EDID_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_EDID_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_EDID_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -734,21 +741,19 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (IS_ERR(device->cdev))
return;
- if (device->cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev->dev.bus_id, device->cdev->id);
- result = sysfs_create_link(&device->dev->dev.kobj,
- &device->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&device->cdev->device.kobj,
- &device->dev->dev.kobj,
- "device");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- }
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev->dev.bus_id, device->cdev->id);
+ result = sysfs_create_link(&device->dev->dev.kobj,
+ &device->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&device->cdev->device.kobj,
+ &device->dev->dev.kobj, "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+
}
if (device->cap._DCS && device->cap._DSS){
static int count = 0;
@@ -1050,87 +1055,82 @@ acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
static int acpi_video_device_add_fs(struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
+ struct proc_dir_entry *entry, *device_dir;
struct acpi_video_device *vid_dev;
-
- if (!device)
- return -ENODEV;
-
vid_dev = acpi_driver_data(device);
if (!vid_dev)
return -ENODEV;
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- vid_dev->video->dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- acpi_device_dir(device)->owner = THIS_MODULE;
- }
+ device_dir = proc_mkdir(acpi_device_bid(device),
+ vid_dev->video->dir);
+ if (!device_dir)
+ return -ENOMEM;
+
+ device_dir->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("info", S_IRUGO, device_dir,
+ &acpi_video_device_info_fops, acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_device_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_dir;
/* 'state' [R/W] */
- entry =
- create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ acpi_video_device_state_fops.write = acpi_video_device_write_state;
+ entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_device_state_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_device_state_fops.write = acpi_video_device_write_state;
- entry->proc_fops = &acpi_video_device_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_info;
/* 'brightness' [R/W] */
- entry =
- create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ acpi_video_device_brightness_fops.write =
+ acpi_video_device_write_brightness;
+ entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_device_brightness_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
- entry->proc_fops = &acpi_video_device_brightness_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_state;
/* 'EDID' [R] */
- entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("EDID", S_IRUGO, device_dir,
+ &acpi_video_device_EDID_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_device_EDID_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_brightness;
+
+ acpi_device_dir(device) = device_dir;
return 0;
+
+ err_remove_brightness:
+ remove_proc_entry("brightness", device_dir);
+ err_remove_state:
+ remove_proc_entry("state", device_dir);
+ err_remove_info:
+ remove_proc_entry("info", device_dir);
+ err_remove_dir:
+ remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
+ return -ENOMEM;
}
static int acpi_video_device_remove_fs(struct acpi_device *device)
{
struct acpi_video_device *vid_dev;
+ struct proc_dir_entry *device_dir;
vid_dev = acpi_driver_data(device);
if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
return -ENODEV;
- if (acpi_device_dir(device)) {
- remove_proc_entry("info", acpi_device_dir(device));
- remove_proc_entry("state", acpi_device_dir(device));
- remove_proc_entry("brightness", acpi_device_dir(device));
- remove_proc_entry("EDID", acpi_device_dir(device));
+ device_dir = acpi_device_dir(device);
+ if (device_dir) {
+ remove_proc_entry("info", device_dir);
+ remove_proc_entry("state", device_dir);
+ remove_proc_entry("brightness", device_dir);
+ remove_proc_entry("EDID", device_dir);
remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
acpi_device_dir(device) = NULL;
}
@@ -1337,94 +1337,81 @@ acpi_video_bus_write_DOS(struct file *file,
static int acpi_video_bus_add_fs(struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
- struct acpi_video_bus *video;
+ struct acpi_video_bus *video = acpi_driver_data(device);
+ struct proc_dir_entry *device_dir;
+ struct proc_dir_entry *entry;
+ device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
+ if (!device_dir)
+ return -ENOMEM;
- video = acpi_driver_data(device);
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_video_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- video->dir = acpi_device_dir(device);
- acpi_device_dir(device)->owner = THIS_MODULE;
- }
+ device_dir->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("info", S_IRUGO, device_dir,
+ &acpi_video_bus_info_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_dir;
/* 'ROM' [R] */
- entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("ROM", S_IRUGO, device_dir,
+ &acpi_video_bus_ROM_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_ROM_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_info;
/* 'POST_info' [R] */
- entry =
- create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("POST_info", S_IRUGO, device_dir,
+ &acpi_video_bus_POST_info_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_POST_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_rom;
/* 'POST' [R/W] */
- entry =
- create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
- acpi_device_dir(device));
+ acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
+ entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_bus_POST_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
- entry->proc_fops = &acpi_video_bus_POST_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_post_info;
/* 'DOS' [R/W] */
- entry =
- create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
- acpi_device_dir(device));
+ acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
+ entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_bus_DOS_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
- entry->proc_fops = &acpi_video_bus_DOS_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_post;
+ video->dir = acpi_device_dir(device) = device_dir;
return 0;
+
+ err_remove_post:
+ remove_proc_entry("POST", device_dir);
+ err_remove_post_info:
+ remove_proc_entry("POST_info", device_dir);
+ err_remove_rom:
+ remove_proc_entry("ROM", device_dir);
+ err_remove_info:
+ remove_proc_entry("info", device_dir);
+ err_remove_dir:
+ remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
+ return -ENOMEM;
}
static int acpi_video_bus_remove_fs(struct acpi_device *device)
{
- struct acpi_video_bus *video;
+ struct proc_dir_entry *device_dir = acpi_device_dir(device);
-
- video = acpi_driver_data(device);
-
- if (acpi_device_dir(device)) {
- remove_proc_entry("info", acpi_device_dir(device));
- remove_proc_entry("ROM", acpi_device_dir(device));
- remove_proc_entry("POST_info", acpi_device_dir(device));
- remove_proc_entry("POST", acpi_device_dir(device));
- remove_proc_entry("DOS", acpi_device_dir(device));
+ if (device_dir) {
+ remove_proc_entry("info", device_dir);
+ remove_proc_entry("ROM", device_dir);
+ remove_proc_entry("POST_info", device_dir);
+ remove_proc_entry("POST", device_dir);
+ remove_proc_entry("DOS", device_dir);
remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
acpi_device_dir(device) = NULL;
}
@@ -1440,11 +1427,15 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
static struct acpi_video_device_attrib*
acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
{
- int count;
+ struct acpi_video_enumerated_device *ids;
+ int i;
+
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if ((ids->value.int_val & 0xffff) == device_id)
+ return &ids->value.attrib;
+ }
- 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;
}
@@ -1571,20 +1562,16 @@ static void
acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device)
{
+ struct acpi_video_enumerated_device *ids;
int i;
-#define IDS_VAL(i) video->attached_array[i].value.int_val
-#define IDS_BIND(i) video->attached_array[i].bind_info
-
- for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
- i < video->attached_count; i++) {
- if (device->device_id == (IDS_VAL(i) & 0xffff)) {
- IDS_BIND(i) = device;
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if (device->device_id == (ids->value.int_val & 0xffff)) {
+ ids->bind_info = device;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
}
}
-#undef IDS_VAL
-#undef IDS_BIND
}
/*
@@ -1603,7 +1590,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
int status;
int count;
int i;
- struct acpi_video_enumerated_device *active_device_list;
+ struct acpi_video_enumerated_device *active_list;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *dod = NULL;
union acpi_object *obj;
@@ -1624,13 +1611,10 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
dod->package.count));
- active_device_list = kmalloc((1 +
- dod->package.count) *
- sizeof(struct
- acpi_video_enumerated_device),
- GFP_KERNEL);
-
- if (!active_device_list) {
+ active_list = kcalloc(1 + dod->package.count,
+ sizeof(struct acpi_video_enumerated_device),
+ GFP_KERNEL);
+ if (!active_list) {
status = -ENOMEM;
goto out;
}
@@ -1640,23 +1624,24 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
obj = &dod->package.elements[i];
if (obj->type != ACPI_TYPE_INTEGER) {
- printk(KERN_ERR PREFIX "Invalid _DOD data\n");
- active_device_list[i].value.int_val =
- ACPI_VIDEO_HEAD_INVALID;
+ printk(KERN_ERR PREFIX
+ "Invalid _DOD data in element %d\n", i);
+ continue;
}
- active_device_list[i].value.int_val = obj->integer.value;
- active_device_list[i].bind_info = NULL;
+
+ active_list[count].value.int_val = obj->integer.value;
+ active_list[count].bind_info = NULL;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
(int)obj->integer.value));
count++;
}
- active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
kfree(video->attached_array);
- video->attached_array = active_device_list;
+ video->attached_array = active_list;
video->attached_count = count;
- out:
+
+ out:
kfree(buffer.pointer);
return status;
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 292aa9a0f02f..9bf2986a2788 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -205,8 +205,8 @@ config SATA_VITESSE
If unsure, say N.
config SATA_INIC162X
- tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Initio 162x SATA support"
+ depends on PCI
help
This option enables support for Initio 162x Serial ATA.
@@ -566,11 +566,11 @@ config PATA_RADISYS
If unsure, say N.
-config PATA_RB500
- tristate "RouterBoard 500 PATA CompactFlash support"
- depends on MIKROTIK_RB500
+config PATA_RB532
+ tristate "RouterBoard 532 PATA CompactFlash support"
+ depends on MIKROTIK_RB532
help
- This option enables support for the RouterBoard 500
+ This option enables support for the RouterBoard 532
PATA CompactFlash controller.
If unsure, say N.
@@ -697,6 +697,15 @@ config PATA_SCC
If unsure, say N.
+config PATA_SCH
+ tristate "Intel SCH PATA support"
+ depends on PCI
+ help
+ This option enables support for Intel SCH PATA on the Intel
+ SCH (US15W, US15L, UL11L) series host controllers.
+
+ If unsure, say N.
+
config PATA_BF54X
tristate "Blackfin 54x ATAPI support"
depends on BF542 || BF548 || BF549
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 1fbc2aa648b7..674965fa326d 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -55,7 +55,7 @@ obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
obj-$(CONFIG_PATA_QDI) += pata_qdi.o
obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
-obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o
+obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
@@ -67,6 +67,7 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
+obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7c4f886f1f16..97f83fb2ee2e 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -358,7 +358,7 @@ static const struct ata_port_info ahci_port_info[] = {
/* board_ahci_sb600 */
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_32BIT_ONLY |
+ AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
@@ -1267,9 +1267,7 @@ static int ahci_check_ready(struct ata_link *link)
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
- if (!(status & ATA_BUSY))
- return 1;
- return 0;
+ return ata_check_ready(status);
}
static int ahci_softreset(struct ata_link *link, unsigned int *class,
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 47aeccd52fa9..75a406f5e694 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -152,6 +152,12 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if (dev->vendor == PCI_VENDOR_ID_AL)
ata_pci_bmdma_clear_simplex(dev);
+ if (dev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(dev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(dev);
+ }
return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL);
}
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index ea2c7649d399..a9027b8fbdd5 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1348,6 +1348,8 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct piix_host_priv *hpriv = host->private_data;
+ struct ata_device *dev0 = &host->ports[0]->link.device[0];
+ u32 scontrol;
int i;
/* check for availability */
@@ -1366,6 +1368,29 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
return;
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
+
+ /* SCR access via SIDPR doesn't work on some configurations.
+ * Give it a test drive by inhibiting power save modes which
+ * we'll do anyway.
+ */
+ scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+
+ /* if IPM is already 3, SCR access is probably working. Don't
+ * un-inhibit power save modes as BIOS might have inhibited
+ * them for a reason.
+ */
+ if ((scontrol & 0xf00) != 0x300) {
+ scontrol |= 0x300;
+ piix_sidpr_write(dev0, SCR_CONTROL, scontrol);
+ scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+
+ if ((scontrol & 0xf00) != 0x300) {
+ dev_printk(KERN_INFO, host->dev, "SCR access via "
+ "SIDPR is available but doesn't work\n");
+ return;
+ }
+ }
+
host->ports[0]->ops = &piix_sidpr_sata_ops;
host->ports[1]->ops = &piix_sidpr_sata_ops;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 51b7d2fad36a..927b692d723c 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3933,6 +3933,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices which get the IVB wrong */
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
+ /* Maybe we should just blacklist TSSTcorp... */
+ { "TSSTcorp CDDVDW SH-S202H", "SB00", ATA_HORKAGE_IVB, },
+ { "TSSTcorp CDDVDW SH-S202H", "SB01", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, },
@@ -6289,6 +6292,7 @@ EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
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_eh_analyze_ncq_error);
EXPORT_SYMBOL_GPL(ata_do_eh);
EXPORT_SYMBOL_GPL(ata_std_error_handler);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 61dcd0026c64..62e033146bed 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1357,7 +1357,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_link *link)
+void ata_eh_analyze_ncq_error(struct ata_link *link)
{
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a34f32442edf..3ce43920e459 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -49,7 +49,11 @@
#include "libata.h"
-#define SECTOR_SIZE 512
+#define SECTOR_SIZE 512
+#define ATA_SCSI_RBUF_SIZE 4096
+
+static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
+static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
@@ -179,6 +183,13 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
ata_scsi_lpm_show, ata_scsi_lpm_put);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
+}
+
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -1632,53 +1643,48 @@ defer:
/**
* ata_scsi_rbuf_get - Map response buffer.
- * @cmd: SCSI command containing buffer to be mapped.
- * @buf_out: Pointer to mapped area.
+ * @flags: unsigned long variable to store irq enable status
+ * @copy_in: copy in from user buffer
*
- * Maps buffer contained within SCSI command @cmd.
+ * Prepare buffer for simulated SCSI commands.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * spin_lock_irqsave(ata_scsi_rbuf_lock) on success
*
* RETURNS:
- * Length of response buffer.
+ * Pointer to response buffer.
*/
-
-static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in,
+ unsigned long *flags)
{
- u8 *buf;
- unsigned int buflen;
-
- struct scatterlist *sg = scsi_sglist(cmd);
+ spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags);
- if (sg) {
- buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
- buflen = sg->length;
- } else {
- buf = NULL;
- buflen = 0;
- }
-
- *buf_out = buf;
- return buflen;
+ memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE);
+ if (copy_in)
+ sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
+ return ata_scsi_rbuf;
}
/**
* ata_scsi_rbuf_put - Unmap response buffer.
* @cmd: SCSI command containing buffer to be unmapped.
- * @buf: buffer to unmap
+ * @copy_out: copy out result
+ * @flags: @flags passed to ata_scsi_rbuf_get()
*
- * Unmaps response buffer contained within @cmd.
+ * Returns rbuf buffer. The result is copied to @cmd's buffer if
+ * @copy_back is true.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * Unlocks ata_scsi_rbuf_lock.
*/
-
-static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
+static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out,
+ unsigned long *flags)
{
- struct scatterlist *sg = scsi_sglist(cmd);
- if (sg)
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ if (copy_out)
+ sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
+ spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags);
}
/**
@@ -1696,24 +1702,17 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen))
+static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+ unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf))
{
u8 *rbuf;
- unsigned int buflen, rc;
+ unsigned int rc;
struct scsi_cmnd *cmd = args->cmd;
unsigned long flags;
- local_irq_save(flags);
-
- buflen = ata_scsi_rbuf_get(cmd, &rbuf);
- memset(rbuf, 0, buflen);
- rc = actor(args, rbuf, buflen);
- ata_scsi_rbuf_put(cmd, rbuf);
-
- local_irq_restore(flags);
+ rbuf = ata_scsi_rbuf_get(cmd, false, &flags);
+ rc = actor(args, rbuf);
+ ata_scsi_rbuf_put(cmd, rc == 0, &flags);
if (rc == 0)
cmd->result = SAM_STAT_GOOD;
@@ -1721,26 +1720,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
}
/**
- * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer
- * @idx: byte index into SCSI response buffer
- * @val: value to set
- *
- * To be used by SCSI command simulator functions. This macros
- * expects two local variables, u8 *rbuf and unsigned int buflen,
- * are in scope.
- *
- * LOCKING:
- * None.
- */
-#define ATA_SCSI_RBUF_SET(idx, val) do { \
- if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \
- } while (0)
-
-/**
* ata_scsiop_inq_std - Simulate INQUIRY command
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns standard device identification data associated
* with non-VPD INQUIRY command output.
@@ -1748,10 +1730,17 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
{
+ const u8 versions[] = {
+ 0x60, /* SAM-3 (no version claimed) */
+
+ 0x03,
+ 0x20, /* SBC-2 (no version claimed) */
+
+ 0x02,
+ 0x60 /* SPC-3 (no version claimed) */
+ };
u8 hdr[] = {
TYPE_DISK,
0,
@@ -1760,35 +1749,21 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
95 - 4
};
+ VPRINTK("ENTER\n");
+
/* set scsi removeable (RMB) bit per ata bit */
if (ata_id_removeable(args->id))
hdr[1] |= (1 << 7);
- VPRINTK("ENTER\n");
-
memcpy(rbuf, hdr, sizeof(hdr));
+ memcpy(&rbuf[8], "ATA ", 8);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
- if (buflen > 35) {
- memcpy(&rbuf[8], "ATA ", 8);
- 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);
- }
-
- if (buflen > 63) {
- const u8 versions[] = {
- 0x60, /* SAM-3 (no version claimed) */
-
- 0x03,
- 0x20, /* SBC-2 (no version claimed) */
+ if (rbuf[32] == 0 || rbuf[32] == ' ')
+ memcpy(&rbuf[32], "n/a ", 4);
- 0x02,
- 0x60 /* SPC-3 (no version claimed) */
- };
-
- memcpy(rbuf + 59, versions, sizeof(versions));
- }
+ memcpy(rbuf + 59, versions, sizeof(versions));
return 0;
}
@@ -1797,27 +1772,22 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns list of inquiry VPD pages available.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
{
const u8 pages[] = {
0x00, /* page 0x00, this page */
0x80, /* page 0x80, unit serial no page */
0x83 /* page 0x83, device ident page */
};
- rbuf[3] = sizeof(pages); /* number of supported VPD pages */
-
- if (buflen > 6)
- memcpy(rbuf + 4, pages, sizeof(pages));
+ rbuf[3] = sizeof(pages); /* number of supported VPD pages */
+ memcpy(rbuf + 4, pages, sizeof(pages));
return 0;
}
@@ -1825,16 +1795,13 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns ATA device serial number.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf)
{
const u8 hdr[] = {
0,
@@ -1842,12 +1809,10 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
0,
ATA_ID_SERNO_LEN, /* page len */
};
- memcpy(rbuf, hdr, sizeof(hdr));
-
- if (buflen > (ATA_ID_SERNO_LEN + 4 - 1))
- ata_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ memcpy(rbuf, hdr, sizeof(hdr));
+ ata_id_string(args->id, (unsigned char *) &rbuf[4],
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
return 0;
}
@@ -1855,7 +1820,6 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Yields two logical unit device identification designators:
* - vendor specific ASCII containing the ATA serial number
@@ -1865,41 +1829,37 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf)
{
- int num;
const int sat_model_serial_desc_len = 68;
+ int num;
rbuf[1] = 0x83; /* this page code */
num = 4;
- 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_ID_SERNO_LEN;
- num += 4;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- 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 */
- /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
- rbuf[num + 0] = 2;
- rbuf[num + 1] = 1;
- rbuf[num + 3] = sat_model_serial_desc_len;
- num += 4;
- memcpy(rbuf + num, "ATA ", 8);
- num += 8;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_PROD, ATA_ID_PROD_LEN);
- num += ATA_ID_PROD_LEN;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
- num += ATA_ID_SERNO_LEN;
- }
+ /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
+ rbuf[num + 0] = 2;
+ rbuf[num + 3] = ATA_ID_SERNO_LEN;
+ num += 4;
+ ata_id_string(args->id, (unsigned char *) rbuf + num,
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
+
+ /* SAT defined lu model and serial numbers descriptor */
+ /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
+ rbuf[num + 0] = 2;
+ rbuf[num + 1] = 1;
+ rbuf[num + 3] = sat_model_serial_desc_len;
+ num += 4;
+ memcpy(rbuf + num, "ATA ", 8);
+ num += 8;
+ ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD,
+ ATA_ID_PROD_LEN);
+ num += ATA_ID_PROD_LEN;
+ ata_id_string(args->id, (unsigned char *) rbuf + num, 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;
}
@@ -1908,35 +1868,26 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Yields SAT-specified ATA VPD page.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
{
- u8 pbuf[60];
struct ata_taskfile tf;
- unsigned int i;
- if (!buflen)
- return 0;
-
- memset(&pbuf, 0, sizeof(pbuf));
memset(&tf, 0, sizeof(tf));
- pbuf[1] = 0x89; /* our page code */
- pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
- pbuf[3] = (0x238 & 0xff);
+ rbuf[1] = 0x89; /* our page code */
+ rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
+ rbuf[3] = (0x238 & 0xff);
- memcpy(&pbuf[8], "linux ", 8);
- memcpy(&pbuf[16], "libata ", 16);
- memcpy(&pbuf[32], DRV_VERSION, 4);
- ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+ memcpy(&rbuf[8], "linux ", 8);
+ memcpy(&rbuf[16], "libata ", 16);
+ memcpy(&rbuf[32], DRV_VERSION, 4);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
/* we don't store the ATA device signature, so we fake it */
@@ -1944,19 +1895,12 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
tf.lbal = 0x1;
tf.nsect = 0x1;
- ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */
- pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
+ ata_tf_to_fis(&tf, 0, 1, &rbuf[36]); /* TODO: PMP? */
+ rbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
- pbuf[56] = ATA_CMD_ID_ATA;
+ rbuf[56] = ATA_CMD_ID_ATA;
- i = min(buflen, 60U);
- memcpy(rbuf, &pbuf[0], i);
- buflen -= i;
-
- if (!buflen)
- return 0;
-
- memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+ memcpy(&rbuf[60], &args->id[0], 512);
return 0;
}
@@ -1964,7 +1908,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* No operation. Simply returns success to caller, to indicate
* that the caller should successfully complete this SCSI command.
@@ -1972,47 +1915,16 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
{
VPRINTK("ENTER\n");
return 0;
}
/**
- * ata_msense_push - Push data onto MODE SENSE data output buffer
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- * @buf: Pointer to BLOB being added to output buffer
- * @buflen: Length of BLOB
- *
- * Store MODE SENSE data on an output buffer.
- *
- * LOCKING:
- * None.
- */
-
-static void ata_msense_push(u8 **ptr_io, const u8 *last,
- const u8 *buf, unsigned int buflen)
-{
- u8 *ptr = *ptr_io;
-
- if ((ptr + buflen - 1) > last)
- return;
-
- memcpy(ptr, buf, buflen);
-
- ptr += buflen;
-
- *ptr_io = ptr;
-}
-
-/**
* ata_msense_caching - Simulate MODE SENSE caching info page
* @id: device IDENTIFY data
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
*
* Generate a caching info page, which conditionally indicates
* write caching to the SCSI layer, depending on device
@@ -2021,58 +1933,43 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last,
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
- const u8 *last)
+static unsigned int ata_msense_caching(u16 *id, u8 *buf)
{
- u8 page[CACHE_MPAGE_LEN];
-
- memcpy(page, def_cache_mpage, sizeof(page));
+ memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage));
if (ata_id_wcache_enabled(id))
- page[2] |= (1 << 2); /* write cache enable */
+ buf[2] |= (1 << 2); /* write cache enable */
if (!ata_id_rahead_enabled(id))
- page[12] |= (1 << 5); /* disable read ahead */
-
- ata_msense_push(ptr_io, last, page, sizeof(page));
- return sizeof(page);
+ buf[12] |= (1 << 5); /* disable read ahead */
+ return sizeof(def_cache_mpage);
}
/**
* ata_msense_ctl_mode - Simulate MODE SENSE control mode page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
*
* Generate a generic MODE SENSE control mode page.
*
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+static unsigned int ata_msense_ctl_mode(u8 *buf)
{
- ata_msense_push(ptr_io, last, def_control_mpage,
- sizeof(def_control_mpage));
+ memcpy(buf, def_control_mpage, sizeof(def_control_mpage));
return sizeof(def_control_mpage);
}
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @bufp: output buffer
*
* Generate a generic MODE SENSE r/w error recovery page.
*
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
+static unsigned int ata_msense_rw_recovery(u8 *buf)
{
-
- ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
- sizeof(def_rw_recovery_mpage));
+ memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage));
return sizeof(def_rw_recovery_mpage);
}
@@ -2104,7 +2001,6 @@ static int ata_dev_supports_fua(u16 *id)
* ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate MODE SENSE commands. Assume this is invoked for direct
* access devices (e.g. disks) only. There should be no block
@@ -2113,19 +2009,17 @@ static int ata_dev_supports_fua(u16 *id)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
{
struct ata_device *dev = args->dev;
- u8 *scsicmd = args->cmd->cmnd, *p, *last;
+ u8 *scsicmd = args->cmd->cmnd, *p = rbuf;
const u8 sat_blk_desc[] = {
0, 0, 0, 0, /* number of blocks: sat unspecified */
0,
0, 0x2, 0x0 /* block length: 512 bytes */
};
u8 pg, spg;
- unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
+ unsigned int ebd, page_control, six_byte;
u8 dpofua;
VPRINTK("ENTER\n");
@@ -2148,17 +2042,10 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
goto invalid_fld;
}
- if (six_byte) {
- output_len = 4 + (ebd ? 8 : 0);
- alloc_len = scsicmd[4];
- } else {
- output_len = 8 + (ebd ? 8 : 0);
- alloc_len = (scsicmd[7] << 8) + scsicmd[8];
- }
- minlen = (alloc_len < buflen) ? alloc_len : buflen;
-
- p = rbuf + output_len;
- last = rbuf + minlen - 1;
+ if (six_byte)
+ p += 4 + (ebd ? 8 : 0);
+ else
+ p += 8 + (ebd ? 8 : 0);
pg = scsicmd[2] & 0x3f;
spg = scsicmd[3];
@@ -2171,61 +2058,48 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
switch(pg) {
case RW_RECOVERY_MPAGE:
- output_len += ata_msense_rw_recovery(&p, last);
+ p += ata_msense_rw_recovery(p);
break;
case CACHE_MPAGE:
- output_len += ata_msense_caching(args->id, &p, last);
+ p += ata_msense_caching(args->id, p);
break;
- case CONTROL_MPAGE: {
- output_len += ata_msense_ctl_mode(&p, last);
+ case CONTROL_MPAGE:
+ p += ata_msense_ctl_mode(p);
break;
- }
case ALL_MPAGES:
- output_len += ata_msense_rw_recovery(&p, last);
- output_len += ata_msense_caching(args->id, &p, last);
- output_len += ata_msense_ctl_mode(&p, last);
+ p += ata_msense_rw_recovery(p);
+ p += ata_msense_caching(args->id, p);
+ p += ata_msense_ctl_mode(p);
break;
default: /* invalid page code */
goto invalid_fld;
}
- if (minlen < 1)
- return 0;
-
dpofua = 0;
if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
(!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
dpofua = 1 << 4;
if (six_byte) {
- output_len--;
- rbuf[0] = output_len;
- if (minlen > 2)
- rbuf[2] |= dpofua;
+ rbuf[0] = p - rbuf - 1;
+ rbuf[2] |= dpofua;
if (ebd) {
- if (minlen > 3)
- rbuf[3] = sizeof(sat_blk_desc);
- if (minlen > 11)
- memcpy(rbuf + 4, sat_blk_desc,
- sizeof(sat_blk_desc));
+ rbuf[3] = sizeof(sat_blk_desc);
+ memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc));
}
} else {
- output_len -= 2;
+ unsigned int output_len = p - rbuf - 2;
+
rbuf[0] = output_len >> 8;
- if (minlen > 1)
- rbuf[1] = output_len;
- if (minlen > 3)
- rbuf[3] |= dpofua;
+ rbuf[1] = output_len;
+ rbuf[3] |= dpofua;
if (ebd) {
- if (minlen > 7)
- rbuf[7] = sizeof(sat_blk_desc);
- if (minlen > 15)
- memcpy(rbuf + 8, sat_blk_desc,
- sizeof(sat_blk_desc));
+ rbuf[7] = sizeof(sat_blk_desc);
+ memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc));
}
}
return 0;
@@ -2245,15 +2119,13 @@ saving_not_supp:
* ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate READ CAPACITY commands.
*
* LOCKING:
* None.
*/
-unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
{
u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
@@ -2264,28 +2136,28 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
last_lba = 0xffffffff;
/* sector count, 32-bit */
- ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3));
- ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2));
- ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1));
- ATA_SCSI_RBUF_SET(3, last_lba);
+ rbuf[0] = last_lba >> (8 * 3);
+ rbuf[1] = last_lba >> (8 * 2);
+ rbuf[2] = last_lba >> (8 * 1);
+ rbuf[3] = last_lba;
/* sector size */
- ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff);
+ rbuf[6] = ATA_SECT_SIZE >> 8;
+ rbuf[7] = ATA_SECT_SIZE & 0xff;
} else {
/* sector count, 64-bit */
- ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
- ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6));
- ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5));
- ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4));
- ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3));
- ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2));
- ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1));
- ATA_SCSI_RBUF_SET(7, last_lba);
+ rbuf[0] = last_lba >> (8 * 7);
+ rbuf[1] = last_lba >> (8 * 6);
+ rbuf[2] = last_lba >> (8 * 5);
+ rbuf[3] = last_lba >> (8 * 4);
+ rbuf[4] = last_lba >> (8 * 3);
+ rbuf[5] = last_lba >> (8 * 2);
+ rbuf[6] = last_lba >> (8 * 1);
+ rbuf[7] = last_lba;
/* sector size */
- ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff);
+ rbuf[10] = ATA_SECT_SIZE >> 8;
+ rbuf[11] = ATA_SECT_SIZE & 0xff;
}
return 0;
@@ -2295,16 +2167,13 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_report_luns - Simulate REPORT LUNS command
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate REPORT LUNS command.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf)
{
VPRINTK("ENTER\n");
rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
@@ -2312,53 +2181,6 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
return 0;
}
-/**
- * ata_scsi_set_sense - Set SCSI sense data and status
- * @cmd: SCSI request to be handled
- * @sk: SCSI-defined sense key
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that builds a valid fixed format, current
- * response code and the given sense key (sk), additional sense
- * code (asc) and additional sense code qualifier (ascq) with
- * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
- * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
- *
- * LOCKING:
- * Not required
- */
-
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
-{
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
-}
-
-/**
- * ata_scsi_badcmd - End a SCSI request with an error
- * @cmd: SCSI request to be handled
- * @done: SCSI command completion function
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that completes a SCSI command with
- * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
- * and the specified additional sense codes.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
-{
- DPRINTK("ENTER\n");
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
-
- done(cmd);
-}
-
static void atapi_sense_complete(struct ata_queued_cmd *qc)
{
if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
@@ -2485,13 +2307,10 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
u8 *scsicmd = cmd->cmnd;
if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
- u8 *buf = NULL;
- unsigned int buflen;
unsigned long flags;
+ u8 *buf;
- local_irq_save(flags);
-
- buflen = ata_scsi_rbuf_get(cmd, &buf);
+ buf = ata_scsi_rbuf_get(cmd, true, &flags);
/* ATAPI devices typically report zero for their SCSI version,
* and sometimes deviate from the spec WRT response data
@@ -2506,9 +2325,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
buf[3] = 0x32;
}
- ata_scsi_rbuf_put(cmd, buf);
-
- local_irq_restore(flags);
+ ata_scsi_rbuf_put(cmd, true, &flags);
}
cmd->result = SAM_STAT_GOOD;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2ec65a8fda79..3c2d2289f85e 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -314,11 +314,7 @@ static int ata_sff_check_ready(struct ata_link *link)
{
u8 status = link->ap->ops->sff_check_status(link->ap);
- if (!(status & ATA_BUSY))
- return 1;
- if (status == 0xff)
- return -ENODEV;
- return 0;
+ return ata_check_ready(status);
}
/**
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ae2cfd95d43e..4514283937ea 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -146,34 +146,6 @@ extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
-extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- u8 asc, u8 ascq);
-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
- u8 sk, u8 asc, u8 ascq);
-extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen));
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index c5f91e629945..fbe605711554 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -259,6 +259,12 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &pacpi_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
+ if (pdev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(pdev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(pdev);
+ }
return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL);
}
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 78738fb4223b..d7de7baf58a8 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -88,8 +88,8 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev,
pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
- pio_mode_data &= ~(0xFF << timing_shift);
- pio_mode_data |= (pio_timings[pio] << timing_shift);
+ pio_timing_data &= ~(0xFF << timing_shift);
+ pio_timing_data |= (pio_timings[pio] << timing_shift);
pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
}
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index a75de0684c15..9ab89732cf94 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1272,8 +1272,8 @@ static void bfin_freeze(struct ata_port *ap)
void bfin_thaw(struct ata_port *ap)
{
+ dev_dbg(ap->dev, "in atapi dma thaw\n");
bfin_check_status(ap);
- bfin_irq_clear(ap);
bfin_irq_on(ap);
}
@@ -1339,13 +1339,130 @@ static int bfin_port_start(struct ata_port *ap)
return 0;
}
+static unsigned int bfin_ata_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u8 status, host_stat = 0;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto idle_irq;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n",
+ ap->print_id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
+
+ /* check altstatus */
+ status = ap->ops->sff_check_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto busy_ata;
+
+ /* check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto busy_ata;
+
+ /* ack bmdma irq events */
+ ap->ops->sff_irq_clear(ap);
+
+ ata_sff_hsm_move(ap, qc, status, 0);
+
+ if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA))
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+busy_ata:
+ return 1; /* irq handled */
+
+idle_irq:
+ ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+ if ((ap->stats.idle_irq % 1000) == 0) {
+ ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+ return 1;
+ }
+#endif
+ return 0; /* irq not handled */
+}
+
+static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ handled |= bfin_ata_host_intr(ap, qc);
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+
static struct scsi_host_template bfin_sht = {
ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = SG_NONE,
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations bfin_pata_ops = {
+static struct ata_port_operations bfin_pata_ops = {
.inherits = &ata_sff_port_ops,
.set_piomode = bfin_set_piomode,
@@ -1370,7 +1487,6 @@ static const struct ata_port_operations bfin_pata_ops = {
.thaw = bfin_thaw,
.softreset = bfin_softreset,
.postreset = bfin_postreset,
- .post_internal_cmd = bfin_bmdma_stop,
.sff_irq_clear = bfin_irq_clear,
.sff_irq_on = bfin_irq_on,
@@ -1507,7 +1623,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
}
if (ata_host_activate(host, platform_get_irq(pdev, 0),
- ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+ bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
peripheral_free_list(atapi_io_port);
dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
return -ENODEV;
diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb532_cf.c
index 4345174aaeec..a108d259f19d 100644
--- a/drivers/ata/pata_rb500_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -32,7 +32,7 @@
#include <asm/gpio.h>
-#define DRV_NAME "pata-rb500-cf"
+#define DRV_NAME "pata-rb532-cf"
#define DRV_VERSION "0.1.0"
#define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash"
@@ -43,7 +43,7 @@
#define RB500_CF_REG_CTRL 0x080E
#define RB500_CF_REG_DATA 0x0C00
-struct rb500_cf_info {
+struct rb532_cf_info {
void __iomem *iobase;
unsigned int gpio_line;
int frozen;
@@ -52,10 +52,10 @@ struct rb500_cf_info {
/* ------------------------------------------------------------------------ */
-static inline void rb500_pata_finish_io(struct ata_port *ap)
+static inline void rb532_pata_finish_io(struct ata_port *ap)
{
struct ata_host *ah = ap->host;
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
ata_sff_altstatus(ap);
ndelay(RB500_CF_IO_DELAY);
@@ -63,14 +63,14 @@ static inline void rb500_pata_finish_io(struct ata_port *ap)
set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
}
-static void rb500_pata_exec_command(struct ata_port *ap,
+static void rb532_pata_exec_command(struct ata_port *ap,
const struct ata_taskfile *tf)
{
writeb(tf->command, ap->ioaddr.command_addr);
- rb500_pata_finish_io(ap);
+ rb532_pata_finish_io(ap);
}
-static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf,
+static void rb532_pata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->link->ap;
@@ -84,27 +84,27 @@ static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf,
*buf = readb(ioaddr);
}
- rb500_pata_finish_io(adev->link->ap);
+ rb532_pata_finish_io(adev->link->ap);
}
-static void rb500_pata_freeze(struct ata_port *ap)
+static void rb532_pata_freeze(struct ata_port *ap)
{
- struct rb500_cf_info *info = ap->host->private_data;
+ struct rb532_cf_info *info = ap->host->private_data;
info->frozen = 1;
}
-static void rb500_pata_thaw(struct ata_port *ap)
+static void rb532_pata_thaw(struct ata_port *ap)
{
- struct rb500_cf_info *info = ap->host->private_data;
+ struct rb532_cf_info *info = ap->host->private_data;
info->frozen = 0;
}
-static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance)
+static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance)
{
struct ata_host *ah = dev_instance;
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
if (gpio_get_value(info->gpio_line)) {
set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW);
@@ -117,30 +117,30 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static struct ata_port_operations rb500_pata_port_ops = {
+static struct ata_port_operations rb532_pata_port_ops = {
.inherits = &ata_sff_port_ops,
- .sff_exec_command = rb500_pata_exec_command,
- .sff_data_xfer = rb500_pata_data_xfer,
- .freeze = rb500_pata_freeze,
- .thaw = rb500_pata_thaw,
+ .sff_exec_command = rb532_pata_exec_command,
+ .sff_data_xfer = rb532_pata_data_xfer,
+ .freeze = rb532_pata_freeze,
+ .thaw = rb532_pata_thaw,
};
/* ------------------------------------------------------------------------ */
-static struct scsi_host_template rb500_pata_sht = {
+static struct scsi_host_template rb532_pata_sht = {
ATA_PIO_SHT(DRV_NAME),
};
/* ------------------------------------------------------------------------ */
-static void rb500_pata_setup_ports(struct ata_host *ah)
+static void rb532_pata_setup_ports(struct ata_host *ah)
{
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
struct ata_port *ap;
ap = ah->ports[0];
- ap->ops = &rb500_pata_port_ops;
+ ap->ops = &rb532_pata_port_ops;
ap->pio_mask = 0x1f; /* PIO4 */
ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
@@ -153,13 +153,13 @@ static void rb500_pata_setup_ports(struct ata_host *ah)
ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA;
}
-static __devinit int rb500_pata_driver_probe(struct platform_device *pdev)
+static __devinit int rb532_pata_driver_probe(struct platform_device *pdev)
{
unsigned int irq;
int gpio;
struct resource *res;
struct ata_host *ah;
- struct rb500_cf_info *info;
+ struct rb532_cf_info *info;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -213,10 +213,10 @@ static __devinit int rb500_pata_driver_probe(struct platform_device *pdev)
goto err_free_gpio;
}
- rb500_pata_setup_ports(ah);
+ rb532_pata_setup_ports(ah);
- ret = ata_host_activate(ah, irq, rb500_pata_irq_handler,
- IRQF_TRIGGER_LOW, &rb500_pata_sht);
+ ret = ata_host_activate(ah, irq, rb532_pata_irq_handler,
+ IRQF_TRIGGER_LOW, &rb532_pata_sht);
if (ret)
goto err_free_gpio;
@@ -228,10 +228,10 @@ err_free_gpio:
return ret;
}
-static __devexit int rb500_pata_driver_remove(struct platform_device *pdev)
+static __devexit int rb532_pata_driver_remove(struct platform_device *pdev)
{
struct ata_host *ah = platform_get_drvdata(pdev);
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
ata_host_detach(ah);
gpio_free(info->gpio_line);
@@ -242,9 +242,9 @@ static __devexit int rb500_pata_driver_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" DRV_NAME);
-static struct platform_driver rb500_pata_platform_driver = {
- .probe = rb500_pata_driver_probe,
- .remove = __devexit_p(rb500_pata_driver_remove),
+static struct platform_driver rb532_pata_platform_driver = {
+ .probe = rb532_pata_driver_probe,
+ .remove = __devexit_p(rb532_pata_driver_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
@@ -255,16 +255,16 @@ static struct platform_driver rb500_pata_platform_driver = {
#define DRV_INFO DRV_DESC " version " DRV_VERSION
-static int __init rb500_pata_module_init(void)
+static int __init rb532_pata_module_init(void)
{
printk(KERN_INFO DRV_INFO "\n");
- return platform_driver_register(&rb500_pata_platform_driver);
+ return platform_driver_register(&rb532_pata_platform_driver);
}
-static void __exit rb500_pata_module_exit(void)
+static void __exit rb532_pata_module_exit(void)
{
- platform_driver_unregister(&rb500_pata_platform_driver);
+ platform_driver_unregister(&rb532_pata_platform_driver);
}
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
@@ -273,5 +273,5 @@ MODULE_DESCRIPTION(DRV_DESC);
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
-module_init(rb500_pata_module_init);
-module_exit(rb500_pata_module_exit);
+module_init(rb532_pata_module_init);
+module_exit(rb532_pata_module_exit);
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
new file mode 100644
index 000000000000..c8cc027789fe
--- /dev/null
+++ b/drivers/ata/pata_sch.c
@@ -0,0 +1,206 @@
+/*
+ * pata_sch.c - Intel SCH PATA controllers
+ *
+ * Copyright (c) 2008 Alek Du <alek.du@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Supports:
+ * Intel SCH (AF82US15W, AF82US15L, AF82UL11L) chipsets -- see spec at:
+ * http://download.intel.com/design/chipsets/embedded/datashts/319537.pdf
+ */
+
+#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/dmi.h>
+
+#define DRV_NAME "pata_sch"
+#define DRV_VERSION "0.2"
+
+/* see SCH datasheet page 351 */
+enum {
+ D0TIM = 0x80, /* Device 0 Timing Register */
+ D1TIM = 0x84, /* Device 1 Timing Register */
+ PM = 0x07, /* PIO Mode Bit Mask */
+ MDM = (0x03 << 8), /* Multi-word DMA Mode Bit Mask */
+ UDM = (0x07 << 16), /* Ultra DMA Mode Bit Mask */
+ PPE = (1 << 30), /* Prefetch/Post Enable */
+ USD = (1 << 31), /* Use Synchronous DMA */
+};
+
+static int sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+
+static const struct pci_device_id sch_pci_tbl[] = {
+ /* Intel SCH PATA Controller */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_IDE), 0 },
+ { } /* terminate list */
+};
+
+static struct pci_driver sch_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sch_pci_tbl,
+ .probe = sch_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static struct scsi_host_template sch_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations sch_pata_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = sch_set_piomode,
+ .set_dmamode = sch_set_dmamode,
+};
+
+static struct ata_port_info sch_port_info = {
+ .flags = 0,
+ .pio_mask = ATA_PIO4, /* pio0-4 */
+ .mwdma_mask = ATA_MWDMA2, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &sch_pata_ops,
+};
+
+MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sch_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ * sch_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_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 port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ /* set PIO mode */
+ data &= ~(PM | PPE);
+ data |= pio;
+ /* enable PPE for block device */
+ if (adev->class == ATA_DEV_ATA)
+ data |= PPE;
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ if (dma_mode >= XFER_UDMA_0) {
+ /* enable Synchronous DMA mode */
+ data |= USD;
+ data &= ~UDM;
+ data |= (dma_mode - XFER_UDMA_0) << 16;
+ } else { /* must be MWDMA mode, since we masked SWDMA already */
+ data &= ~(USD | MDM);
+ data |= (dma_mode - XFER_MW_DMA_0) << 8;
+ }
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_init_one - Register SCH ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in sch_pci_tbl matching with @pdev
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int __devinit sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int printed_version;
+ const struct ata_port_info *ppi[] = { &sch_port_info, NULL };
+ struct ata_host *host;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* enable device and prepare host */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ if (rc)
+ return rc;
+ pci_set_master(pdev);
+ return ata_pci_sff_activate_host(host, ata_sff_interrupt, &sch_sht);
+}
+
+static int __init sch_init(void)
+{
+ return pci_register_driver(&sch_pci_driver);
+}
+
+static void __exit sch_exit(void)
+{
+ pci_unregister_driver(&sch_pci_driver);
+}
+
+module_init(sch_init);
+module_exit(sch_exit);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index d4840748fb5c..2fea6cbe7755 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -464,11 +464,12 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
pci_dev_put(isa);
- /* 0x40 low bits indicate enabled channels */
- pci_read_config_byte(pdev, 0x40 , &enable);
- enable &= 3;
- if (enable == 0) {
- return -ENODEV;
+ if (!(config->flags & VIA_NO_ENABLES)) {
+ /* 0x40 low bits indicate enabled channels */
+ pci_read_config_byte(pdev, 0x40 , &enable);
+ enable &= 3;
+ if (enable == 0)
+ return -ENODEV;
}
/* Initialise the FIFO for the enabled channels. */
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index d27bb9a2568f..3ead02fe379e 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -10,13 +10,33 @@
* 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.
+ * This driver has interesting history. The first version was written
+ * from the documentation and a 2.4 IDE driver posted on a Taiwan
+ * company, which didn't use any IDMA features and couldn't handle
+ * LBA48. The resulting driver couldn't handle LBA48 devices either
+ * making it pretty useless.
+ *
+ * After a while, initio picked the driver up, renamed it to
+ * sata_initio162x, updated it to use IDMA for ATA DMA commands and
+ * posted it on their website. It only used ATA_PROT_DMA for IDMA and
+ * attaching both devices and issuing IDMA and !IDMA commands
+ * simultaneously broke it due to PIRQ masking interaction but it did
+ * show how to use the IDMA (ADMA + some initio specific twists)
+ * engine.
+ *
+ * Then, I picked up their changes again and here's the usable driver
+ * which uses IDMA for everything. Everything works now including
+ * LBA48, CD/DVD burning, suspend/resume and hotplug. There are some
+ * issues tho. Result Tf is not resported properly, NCQ isn't
+ * supported yet and CD/DVD writing works with DMA assisted PIO
+ * protocol (which, for native SATA devices, shouldn't cause any
+ * noticeable difference).
+ *
+ * Anyways, so, here's finally a working driver for inic162x. Enjoy!
+ *
+ * initio: If you guys wanna improve the driver regarding result TF
+ * access and other stuff, please feel free to contact me. I'll be
+ * happy to assist.
*/
#include <linux/kernel.h>
@@ -28,13 +48,19 @@
#include <scsi/scsi_device.h>
#define DRV_NAME "sata_inic162x"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
enum {
- MMIO_BAR = 5,
+ MMIO_BAR_PCI = 5,
+ MMIO_BAR_CARDBUS = 1,
NR_PORTS = 2,
+ IDMA_CPB_TBL_SIZE = 4 * 32,
+
+ INIC_DMA_BOUNDARY = 0xffffff,
+
+ HOST_ACTRL = 0x08,
HOST_CTL = 0x7c,
HOST_STAT = 0x7e,
HOST_IRQ_STAT = 0xbc,
@@ -43,22 +69,37 @@ enum {
PORT_SIZE = 0x40,
/* registers for ATA TF operation */
- PORT_TF = 0x00,
- PORT_ALT_STAT = 0x08,
+ PORT_TF_DATA = 0x00,
+ PORT_TF_FEATURE = 0x01,
+ PORT_TF_NSECT = 0x02,
+ PORT_TF_LBAL = 0x03,
+ PORT_TF_LBAM = 0x04,
+ PORT_TF_LBAH = 0x05,
+ PORT_TF_DEVICE = 0x06,
+ PORT_TF_COMMAND = 0x07,
+ PORT_TF_ALT_STAT = 0x08,
PORT_IRQ_STAT = 0x09,
PORT_IRQ_MASK = 0x0a,
PORT_PRD_CTL = 0x0b,
PORT_PRD_ADDR = 0x0c,
PORT_PRD_XFERLEN = 0x10,
+ PORT_CPB_CPBLAR = 0x18,
+ PORT_CPB_PTQFIFO = 0x1c,
/* IDMA register */
PORT_IDMA_CTL = 0x14,
+ PORT_IDMA_STAT = 0x16,
+
+ PORT_RPQ_FIFO = 0x1e,
+ PORT_RPQ_CNT = 0x1f,
PORT_SCR = 0x20,
/* HOST_CTL bits */
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
- HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_FTHD0 = (1 << 10), /* fifo threshold 0 */
+ HCTL_FTHD1 = (1 << 11), /* fifo threshold 1*/
+ HCTL_PWRDWN = (1 << 12), /* power down PHYs */
HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
HCTL_RPGSEL = (1 << 15), /* register page select */
@@ -81,9 +122,7 @@ enum {
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_DEFAULT = PIRQ_REPLY | PIRQ_ATA,
PIRQ_MASK_FREEZE = 0xff,
/* PORT_PRD_CTL bits */
@@ -96,20 +135,104 @@ enum {
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 */
+
+ /* PORT_IDMA_STAT bits */
+ IDMA_STAT_PERR = (1 << 0), /* PCI ERROR MODE */
+ IDMA_STAT_CPBERR = (1 << 1), /* ADMA CPB error */
+ IDMA_STAT_LGCY = (1 << 3), /* ADMA legacy */
+ IDMA_STAT_UIRQ = (1 << 4), /* ADMA unsolicited irq */
+ IDMA_STAT_STPD = (1 << 5), /* ADMA stopped */
+ IDMA_STAT_PSD = (1 << 6), /* ADMA pause */
+ IDMA_STAT_DONE = (1 << 7), /* ADMA done */
+
+ IDMA_STAT_ERR = IDMA_STAT_PERR | IDMA_STAT_CPBERR,
+
+ /* CPB Control Flags*/
+ CPB_CTL_VALID = (1 << 0), /* CPB valid */
+ CPB_CTL_QUEUED = (1 << 1), /* queued command */
+ CPB_CTL_DATA = (1 << 2), /* data, rsvd in datasheet */
+ CPB_CTL_IEN = (1 << 3), /* PCI interrupt enable */
+ CPB_CTL_DEVDIR = (1 << 4), /* device direction control */
+
+ /* CPB Response Flags */
+ CPB_RESP_DONE = (1 << 0), /* ATA command complete */
+ CPB_RESP_REL = (1 << 1), /* ATA release */
+ CPB_RESP_IGNORED = (1 << 2), /* CPB ignored */
+ CPB_RESP_ATA_ERR = (1 << 3), /* ATA command error */
+ CPB_RESP_SPURIOUS = (1 << 4), /* ATA spurious interrupt error */
+ CPB_RESP_UNDERFLOW = (1 << 5), /* APRD deficiency length error */
+ CPB_RESP_OVERFLOW = (1 << 6), /* APRD exccess length error */
+ CPB_RESP_CPB_ERR = (1 << 7), /* CPB error flag */
+
+ /* PRD Control Flags */
+ PRD_DRAIN = (1 << 1), /* ignore data excess */
+ PRD_CDB = (1 << 2), /* atapi packet command pointer */
+ PRD_DIRECT_INTR = (1 << 3), /* direct interrupt */
+ PRD_DMA = (1 << 4), /* data transfer method */
+ PRD_WRITE = (1 << 5), /* data dir, rsvd in datasheet */
+ PRD_IOM = (1 << 6), /* io/memory transfer */
+ PRD_END = (1 << 7), /* APRD chain end */
};
+/* Comman Parameter Block */
+struct inic_cpb {
+ u8 resp_flags; /* Response Flags */
+ u8 error; /* ATA Error */
+ u8 status; /* ATA Status */
+ u8 ctl_flags; /* Control Flags */
+ __le32 len; /* Total Transfer Length */
+ __le32 prd; /* First PRD pointer */
+ u8 rsvd[4];
+ /* 16 bytes */
+ u8 feature; /* ATA Feature */
+ u8 hob_feature; /* ATA Ex. Feature */
+ u8 device; /* ATA Device/Head */
+ u8 mirctl; /* Mirror Control */
+ u8 nsect; /* ATA Sector Count */
+ u8 hob_nsect; /* ATA Ex. Sector Count */
+ u8 lbal; /* ATA Sector Number */
+ u8 hob_lbal; /* ATA Ex. Sector Number */
+ u8 lbam; /* ATA Cylinder Low */
+ u8 hob_lbam; /* ATA Ex. Cylinder Low */
+ u8 lbah; /* ATA Cylinder High */
+ u8 hob_lbah; /* ATA Ex. Cylinder High */
+ u8 command; /* ATA Command */
+ u8 ctl; /* ATA Control */
+ u8 slave_error; /* Slave ATA Error */
+ u8 slave_status; /* Slave ATA Status */
+ /* 32 bytes */
+} __packed;
+
+/* Physical Region Descriptor */
+struct inic_prd {
+ __le32 mad; /* Physical Memory Address */
+ __le16 len; /* Transfer Length */
+ u8 rsvd;
+ u8 flags; /* Control Flags */
+} __packed;
+
+struct inic_pkt {
+ struct inic_cpb cpb;
+ struct inic_prd prd[LIBATA_MAX_PRD + 1]; /* + 1 for cdb */
+ u8 cdb[ATAPI_CDB_LEN];
+} __packed;
+
struct inic_host_priv {
- u16 cached_hctl;
+ void __iomem *mmio_base;
+ u16 cached_hctl;
};
struct inic_port_priv {
- u8 dfl_prdctl;
- u8 cached_prdctl;
- u8 cached_pirq_mask;
+ struct inic_pkt *pkt;
+ dma_addr_t pkt_dma;
+ u32 *cpb_tbl;
+ dma_addr_t cpb_tbl_dma;
};
static struct scsi_host_template inic_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */
+ .dma_boundary = INIC_DMA_BOUNDARY,
};
static const int scr_map[] = {
@@ -120,54 +243,34 @@ static const int scr_map[] = {
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;
+ struct inic_host_priv *hpriv = ap->host->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);
+ return hpriv->mmio_base + ap->port_no * PORT_SIZE;
}
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);
+ /* stop IDMA engine */
+ readw(idma_ctl); /* flush */
+ msleep(1);
/* mask IRQ and assert reset */
- writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(IDMA_CTL_RST_IDMA, idma_ctl);
readw(idma_ctl); /* flush */
-
- /* give it some time */
msleep(1);
/* release reset */
- writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(0, idma_ctl);
/* clear irq */
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- /* reenable ATA IRQ, turn off IDMA mode */
- writew(ctl, idma_ctl);
}
static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -184,120 +287,126 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
- void __iomem *addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
- addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
return 0;
}
-/*
- * 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)
+static void inic_stop_idma(struct ata_port *ap)
{
- 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->sff_exec_command(ap, &qc->tf);
+ readb(port_base + PORT_RPQ_FIFO);
+ readb(port_base + PORT_RPQ_CNT);
+ writew(0, port_base + PORT_IDMA_CTL);
}
-static void inic_bmdma_start(struct ata_queued_cmd *qc)
+static void inic_host_err_intr(struct ata_port *ap, u8 irq_stat, u16 idma_stat)
{
- struct ata_port *ap = qc->ap;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ struct inic_cpb *cpb = &pp->pkt->cpb;
+ bool freeze = false;
- /* start host DMA transaction */
- pp->cached_prdctl |= PRD_CTL_START;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-}
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x idma_stat=0x%x",
+ irq_stat, idma_stat);
-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);
+ inic_stop_idma(ap);
- /* stop DMA engine */
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
-}
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_push_desc(ehi, "hotplug");
+ ata_ehi_hotplugged(ehi);
+ freeze = true;
+ }
-static u8 inic_bmdma_status(struct ata_port *ap)
-{
- /* event is already verified by the interrupt handler */
- return ATA_DMA_INTR;
+ if (idma_stat & IDMA_STAT_PERR) {
+ ata_ehi_push_desc(ehi, "PCI error");
+ freeze = true;
+ }
+
+ if (idma_stat & IDMA_STAT_CPBERR) {
+ ata_ehi_push_desc(ehi, "CPB error");
+
+ if (cpb->resp_flags & CPB_RESP_IGNORED) {
+ __ata_ehi_push_desc(ehi, " ignored");
+ ehi->err_mask |= AC_ERR_INVALID;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags & CPB_RESP_ATA_ERR)
+ ehi->err_mask |= AC_ERR_DEV;
+
+ if (cpb->resp_flags & CPB_RESP_SPURIOUS) {
+ __ata_ehi_push_desc(ehi, " spurious-intr");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags &
+ (CPB_RESP_UNDERFLOW | CPB_RESP_OVERFLOW)) {
+ __ata_ehi_push_desc(ehi, " data-over/underflow");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+ }
+
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
}
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 irq_stat;
+ u16 idma_stat;
- /* fetch and clear irq */
+ /* read and clear IRQ status */
irq_stat = readb(port_base + PORT_IRQ_STAT);
writeb(irq_stat, port_base + PORT_IRQ_STAT);
+ idma_stat = readw(port_base + PORT_IDMA_STAT);
- if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->link.active_tag);
+ if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
+ inic_host_err_intr(ap, irq_stat, idma_stat);
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- return;
- }
+ if (unlikely(!qc))
+ goto spurious;
- if (likely(ata_sff_host_intr(ap, qc)))
- return;
+ if (likely(idma_stat & IDMA_STAT_DONE)) {
+ inic_stop_idma(ap);
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- ata_port_printk(ap, KERN_WARNING, "unhandled "
- "interrupt, irq_stat=%x\n", irq_stat);
+ /* Depending on circumstances, device error
+ * isn't reported by IDMA, check it explicitly.
+ */
+ if (unlikely(readb(port_base + PORT_TF_COMMAND) &
+ (ATA_DF | ATA_ERR)))
+ qc->err_mask |= AC_ERR_DEV;
+
+ ata_qc_complete(qc);
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);
+ spurious:
+ ata_port_printk(ap, KERN_WARNING, "unhandled interrupt: "
+ "cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n",
+ qc ? qc->tf.command : 0xff, irq_stat, idma_stat);
}
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ struct inic_host_priv *hpriv = host->private_data;
u16 host_irq_stat;
int i, handled = 0;;
- host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+ host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
goto out;
@@ -327,60 +436,173 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+static int inic_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ /* For some reason ATAPI_PROT_DMA doesn't work for some
+ * commands including writes and other misc ops. Use PIO
+ * protocol instead, which BTW is driven by the DMA engine
+ * anyway, so it shouldn't make much difference for native
+ * SATA devices.
+ */
+ if (atapi_cmd_type(qc->cdb[0]) == READ)
+ return 0;
+ return 1;
+}
+
+static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ unsigned int si;
+ u8 flags = 0;
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ flags |= PRD_WRITE;
+
+ if (ata_is_dma(qc->tf.protocol))
+ flags |= PRD_DMA;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ prd->mad = cpu_to_le32(sg_dma_address(sg));
+ prd->len = cpu_to_le16(sg_dma_len(sg));
+ prd->flags = flags;
+ prd++;
+ }
+
+ WARN_ON(!si);
+ prd[-1].flags |= PRD_END;
+}
+
+static void inic_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct inic_port_priv *pp = qc->ap->private_data;
+ struct inic_pkt *pkt = pp->pkt;
+ struct inic_cpb *cpb = &pkt->cpb;
+ struct inic_prd *prd = pkt->prd;
+ bool is_atapi = ata_is_atapi(qc->tf.protocol);
+ bool is_data = ata_is_data(qc->tf.protocol);
+ unsigned int cdb_len = 0;
+
+ VPRINTK("ENTER\n");
+
+ if (is_atapi)
+ cdb_len = qc->dev->cdb_len;
+
+ /* prepare packet, based on initio driver */
+ memset(pkt, 0, sizeof(struct inic_pkt));
+
+ cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
+ if (is_atapi || is_data)
+ cpb->ctl_flags |= CPB_CTL_DATA;
+
+ cpb->len = cpu_to_le32(qc->nbytes + cdb_len);
+ cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
+
+ cpb->device = qc->tf.device;
+ cpb->feature = qc->tf.feature;
+ cpb->nsect = qc->tf.nsect;
+ cpb->lbal = qc->tf.lbal;
+ cpb->lbam = qc->tf.lbam;
+ cpb->lbah = qc->tf.lbah;
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48) {
+ cpb->hob_feature = qc->tf.hob_feature;
+ cpb->hob_nsect = qc->tf.hob_nsect;
+ cpb->hob_lbal = qc->tf.hob_lbal;
+ cpb->hob_lbam = qc->tf.hob_lbam;
+ cpb->hob_lbah = qc->tf.hob_lbah;
+ }
+
+ cpb->command = qc->tf.command;
+ /* don't load ctl - dunno why. it's like that in the initio driver */
+
+ /* setup PRD for CDB */
+ if (is_atapi) {
+ memcpy(pkt->cdb, qc->cdb, ATAPI_CDB_LEN);
+ prd->mad = cpu_to_le32(pp->pkt_dma +
+ offsetof(struct inic_pkt, cdb));
+ prd->len = cpu_to_le16(cdb_len);
+ prd->flags = PRD_CDB | PRD_WRITE;
+ if (!is_data)
+ prd->flags |= PRD_END;
+ prd++;
+ }
+
+ /* setup sg table */
+ if (is_data)
+ inic_fill_sg(prd, qc);
+
+ pp->cpb_tbl[0] = pp->pkt_dma;
+}
+
static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ void __iomem *port_base = inic_port_base(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);
+ /* fire up the ADMA engine */
+ writew(HCTL_FTHD0, port_base + HOST_CTL);
+ writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
+ writeb(0, port_base + PORT_CPB_PTQFIFO);
+
+ return 0;
+}
+
+static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ tf->feature = readb(port_base + PORT_TF_FEATURE);
+ tf->nsect = readb(port_base + PORT_TF_NSECT);
+ tf->lbal = readb(port_base + PORT_TF_LBAL);
+ tf->lbam = readb(port_base + PORT_TF_LBAM);
+ tf->lbah = readb(port_base + PORT_TF_LBAH);
+ tf->device = readb(port_base + PORT_TF_DEVICE);
+ tf->command = readb(port_base + PORT_TF_COMMAND);
+}
- /* 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.
+static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *rtf = &qc->result_tf;
+ struct ata_taskfile tf;
+
+ /* FIXME: Except for status and error, result TF access
+ * doesn't work. I tried reading from BAR0/2, CPB and BAR5.
+ * None works regardless of which command interface is used.
+ * For now return true iff status indicates device error.
+ * This means that we're reporting bogus sector for RW
+ * failures. Eeekk....
*/
- if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
- qc->tf.command == ATA_CMD_ID_ATAPI)) {
- u8 stat = ap->ops->sff_check_status(ap);
- if (stat == 0x7f || stat == 0xff)
- return AC_ERR_HSM;
- }
+ inic_tf_read(qc->ap, &tf);
- return ata_sff_qc_issue(qc);
+ if (!(tf.command & ATA_ERR))
+ return false;
+
+ rtf->command = tf.command;
+ rtf->feature = tf.feature;
+ return true;
}
static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
-
- ap->ops->sff_check_status(ap);
+ writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
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);
- ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
+ writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
+}
- __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+static int inic_check_ready(struct ata_link *link)
+{
+ void __iomem *port_base = inic_port_base(link->ap);
- readb(port_base + PORT_IRQ_STAT); /* flush */
+ return ata_check_ready(readb(port_base + PORT_TF_COMMAND));
}
/*
@@ -394,17 +616,15 @@ static int inic_hardreset(struct ata_link *link, 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(&link->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);
+ writew(IDMA_CTL_RST_ATA, idma_ctl);
readw(idma_ctl); /* flush */
msleep(1);
- writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+ writew(0, idma_ctl);
rc = sata_link_resume(link, timing, deadline);
if (rc) {
@@ -418,7 +638,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
struct ata_taskfile tf;
/* wait for link to become ready */
- rc = ata_sff_wait_after_reset(link, 1, deadline);
+ rc = ata_wait_after_reset(link, deadline, inic_check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_WARNING, "device not ready "
@@ -426,7 +646,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
return rc;
}
- ata_sff_tf_read(ap, &tf);
+ inic_tf_read(ap, &tf);
*class = ata_dev_classify(&tf);
}
@@ -436,18 +656,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
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_std_error_handler(ap);
}
@@ -458,26 +668,18 @@ static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
inic_reset_port(inic_port_base(qc->ap));
}
-static void inic_dev_config(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;
-
- if (dev->n_sectors >= 1 << 28) {
- ata_dev_printk(dev, KERN_ERR,
- "ERROR: This driver doesn't support LBA48 yet and may cause\n"
- " data corruption on such devices. Disabling.\n");
- ata_dev_disable(dev);
- }
-}
-
static void init_port(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
- /* Setup PRD address */
+ /* clear packet and CPB table */
+ memset(pp->pkt, 0, sizeof(struct inic_pkt));
+ memset(pp->cpb_tbl, 0, IDMA_CPB_TBL_SIZE);
+
+ /* setup PRD and CPB lookup table addresses */
writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+ writel(pp->cpb_tbl_dma, port_base + PORT_CPB_CPBLAR);
}
static int inic_port_resume(struct ata_port *ap)
@@ -488,28 +690,30 @@ static int inic_port_resume(struct ata_port *ap)
static int inic_port_start(struct ata_port *ap)
{
- void __iomem *port_base = inic_port_base(ap);
+ struct device *dev = ap->host->dev;
struct inic_port_priv *pp;
- u8 tmp;
int rc;
/* alloc and initialize private data */
- pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(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);
+ if (rc)
return rc;
- }
+
+ pp->pkt = dmam_alloc_coherent(dev, sizeof(struct inic_pkt),
+ &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
+
+ pp->cpb_tbl = dmam_alloc_coherent(dev, IDMA_CPB_TBL_SIZE,
+ &pp->cpb_tbl_dma, GFP_KERNEL);
+ if (!pp->cpb_tbl)
+ return -ENOMEM;
init_port(ap);
@@ -517,21 +721,18 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &sata_port_ops,
- .bmdma_setup = inic_bmdma_setup,
- .bmdma_start = inic_bmdma_start,
- .bmdma_stop = inic_bmdma_stop,
- .bmdma_status = inic_bmdma_status,
+ .check_atapi_dma = inic_check_atapi_dma,
+ .qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
+ .qc_fill_rtf = inic_qc_fill_rtf,
.freeze = inic_freeze,
.thaw = inic_thaw,
- .softreset = ATA_OP_NULL, /* softreset is broken */
.hardreset = inic_hardreset,
.error_handler = inic_error_handler,
.post_internal_cmd = inic_post_internal_cmd,
- .dev_config = inic_dev_config,
.scr_read = inic_scr_read,
.scr_write = inic_scr_write,
@@ -541,12 +742,6 @@ static struct ata_port_operations inic_port_ops = {
};
static struct ata_port_info inic_port_info = {
- /* For some reason, ATAPI_PROT_PIO 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 */
@@ -599,7 +794,6 @@ 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;
rc = ata_pci_device_do_resume(pdev);
@@ -607,7 +801,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = init_controller(mmio_base, hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc)
return rc;
}
@@ -625,6 +819,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_host *host;
struct inic_host_priv *hpriv;
void __iomem * const *iomap;
+ int mmio_bar;
int i, rc;
if (!printed_version++)
@@ -638,38 +833,31 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->private_data = hpriv;
- /* acquire resources and fill host */
+ /* Acquire resources and fill host. Note that PCI and cardbus
+ * use different BARs.
+ */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ if (pci_resource_flags(pdev, MMIO_BAR_PCI) & IORESOURCE_MEM)
+ mmio_bar = MMIO_BAR_PCI;
+ else
+ mmio_bar = MMIO_BAR_CARDBUS;
+
+ rc = pcim_iomap_regions(pdev, 1 << mmio_bar, DRV_NAME);
if (rc)
return rc;
host->iomap = iomap = pcim_iomap_table(pdev);
+ hpriv->mmio_base = iomap[mmio_bar];
+ hpriv->cached_hctl = readw(hpriv->mmio_base + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
struct ata_port *ap = host->ports[i];
- struct ata_ioports *port = &ap->ioaddr;
- unsigned int offset = 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 = iomap[MMIO_BAR] + offset + PORT_SCR;
-
- ata_sff_std_ports(port);
-
- ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
- ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 2 * i),
- (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
- ATA_PCI_CTL_OFS);
- }
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+ ata_port_pbar_desc(ap, mmio_bar, -1, "mmio");
+ ata_port_pbar_desc(ap, mmio_bar, i * PORT_SIZE, "port");
+ }
/* Set dma_mask. This devices doesn't support 64bit addressing. */
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
@@ -698,7 +886,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
- rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to initialize controller\n");
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 26a6337195b3..bb73b2222627 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -65,6 +65,7 @@
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
+#include <linux/bitops.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -91,9 +92,9 @@ enum {
MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
MV_SATAHC0_REG_BASE = 0x20000,
- MV_FLASH_CTL = 0x1046c,
- MV_GPIO_PORT_CTL = 0x104f0,
- MV_RESET_CFG = 0x180d8,
+ MV_FLASH_CTL_OFS = 0x1046c,
+ MV_GPIO_PORT_CTL_OFS = 0x104f0,
+ MV_RESET_CFG_OFS = 0x180d8,
MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
@@ -147,18 +148,21 @@ enum {
/* PCI interface registers */
PCI_COMMAND_OFS = 0xc00,
+ PCI_COMMAND_MRDTRIG = (1 << 7), /* PCI Master Read Trigger */
PCI_MAIN_CMD_STS_OFS = 0xd30,
STOP_PCI_MASTER = (1 << 2),
PCI_MASTER_EMPTY = (1 << 3),
GLOB_SFT_RST = (1 << 4),
- MV_PCI_MODE = 0xd00,
+ MV_PCI_MODE_OFS = 0xd00,
+ MV_PCI_MODE_MASK = 0x30,
+
MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
MV_PCI_DISC_TIMER = 0xd04,
MV_PCI_MSI_TRIGGER = 0xc38,
MV_PCI_SERR_MASK = 0xc28,
- MV_PCI_XBAR_TMOUT = 0x1d04,
+ MV_PCI_XBAR_TMOUT_OFS = 0x1d04,
MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
MV_PCI_ERR_ATTRIBUTE = 0x1d48,
@@ -172,10 +176,11 @@ enum {
PCIE_IRQ_MASK_OFS = 0x1910,
PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */
- HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
- HC_MAIN_IRQ_MASK_OFS = 0x1d64,
- HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
- HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
+ /* Host Controller Main Interrupt Cause/Mask registers (1 per-chip) */
+ PCI_HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
+ PCI_HC_MAIN_IRQ_MASK_OFS = 0x1d64,
+ SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020,
+ SOC_HC_MAIN_IRQ_MASK_OFS = 0x20024,
ERR_IRQ = (1 << 0), /* shift by port # */
DONE_IRQ = (1 << 1), /* shift by port # */
HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
@@ -224,16 +229,18 @@ enum {
PHY_MODE4 = 0x314,
PHY_MODE2 = 0x330,
SATA_IFCTL_OFS = 0x344,
+ SATA_TESTCTL_OFS = 0x348,
SATA_IFSTAT_OFS = 0x34c,
VENDOR_UNIQUE_FIS_OFS = 0x35c,
- FIS_CFG_OFS = 0x360,
- FIS_CFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
+ FISCFG_OFS = 0x360,
+ FISCFG_WAIT_DEV_ERR = (1 << 8), /* wait for host on DevErr */
+ FISCFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
MV5_PHY_MODE = 0x74,
- MV5_LT_MODE = 0x30,
- MV5_PHY_CTL = 0x0C,
- SATA_INTERFACE_CFG = 0x050,
+ MV5_LTMODE_OFS = 0x30,
+ MV5_PHY_CTL_OFS = 0x0C,
+ SATA_INTERFACE_CFG_OFS = 0x050,
MV_M2_PREAMP_MASK = 0x7e0,
@@ -331,10 +338,16 @@ enum {
EDMA_CMD_OFS = 0x28, /* EDMA command register */
EDMA_EN = (1 << 0), /* enable EDMA */
EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
- ATA_RST = (1 << 2), /* reset trans/link/phy */
+ EDMA_RESET = (1 << 2), /* reset eng/trans/link/phy */
+
+ EDMA_STATUS_OFS = 0x30, /* EDMA engine status */
+ EDMA_STATUS_CACHE_EMPTY = (1 << 6), /* GenIIe command cache empty */
+ EDMA_STATUS_IDLE = (1 << 7), /* GenIIe EDMA enabled/idle */
- EDMA_IORDY_TMOUT = 0x34,
- EDMA_ARB_CFG = 0x38,
+ EDMA_IORDY_TMOUT_OFS = 0x34,
+ EDMA_ARB_CFG_OFS = 0x38,
+
+ EDMA_HALTCOND_OFS = 0x60, /* GenIIe halt conditions */
GEN_II_NCQ_MAX_SECTORS = 256, /* max sects/io on Gen2 w/NCQ */
@@ -349,15 +362,19 @@ enum {
MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
+ MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
MV_PP_FLAG_NCQ_EN = (1 << 1), /* is EDMA set up for NCQ? */
+ MV_PP_FLAG_FBS_EN = (1 << 2), /* is EDMA set up for FBS? */
+ MV_PP_FLAG_DELAYED_EH = (1 << 3), /* delayed dev err handling */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
+#define IS_PCIE(hpriv) ((hpriv)->hp_flags & MV_HP_PCIE)
#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
#define WINDOW_CTRL(i) (0x20030 + ((i) << 4))
@@ -432,6 +449,7 @@ struct mv_port_priv {
unsigned int resp_idx;
u32 pp_flags;
+ unsigned int delayed_eh_pmp_map;
};
struct mv_port_signal {
@@ -445,8 +463,8 @@ struct mv_host_priv {
const struct mv_hw_ops *ops;
int n_ports;
void __iomem *base;
- void __iomem *main_cause_reg_addr;
- void __iomem *main_mask_reg_addr;
+ void __iomem *main_irq_cause_addr;
+ void __iomem *main_irq_mask_addr;
u32 irq_cause_ofs;
u32 irq_mask_ofs;
u32 unmask_all_irqs;
@@ -478,6 +496,7 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
+static int mv_qc_defer(struct ata_queued_cmd *qc);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
@@ -526,6 +545,9 @@ static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int mv_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static void mv_pmp_error_handler(struct ata_port *ap);
+static void mv_process_crpb_entries(struct ata_port *ap,
+ struct mv_port_priv *pp);
/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
* because we have to allow room for worst case splitting of
@@ -547,6 +569,7 @@ static struct scsi_host_template mv6_sht = {
static struct ata_port_operations mv5_ops = {
.inherits = &ata_sff_port_ops,
+ .qc_defer = mv_qc_defer,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -565,7 +588,6 @@ static struct ata_port_operations mv5_ops = {
static struct ata_port_operations mv6_ops = {
.inherits = &mv5_ops,
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
.dev_config = mv6_dev_config,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -573,12 +595,11 @@ static struct ata_port_operations mv6_ops = {
.pmp_hardreset = mv_pmp_hardreset,
.pmp_softreset = mv_softreset,
.softreset = mv_softreset,
- .error_handler = sata_pmp_error_handler,
+ .error_handler = mv_pmp_error_handler,
};
static struct ata_port_operations mv_iie_ops = {
.inherits = &mv6_ops,
- .qc_defer = ata_std_qc_defer, /* FIS-based switching */
.dev_config = ATA_OP_NULL,
.qc_prep = mv_qc_prep_iie,
};
@@ -727,8 +748,8 @@ static inline unsigned int mv_hardport_from_port(unsigned int port)
* Simple code, with two return values, so macro rather than inline.
*
* port is the sole input, in range 0..7.
- * shift is one output, for use with the main_cause and main_mask registers.
- * hardport is the other output, in range 0..3
+ * shift is one output, for use with main_irq_cause / main_irq_mask registers.
+ * hardport is the other output, in range 0..3.
*
* Note that port and hardport may be the same variable in some cases.
*/
@@ -874,6 +895,29 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
}
}
+static void mv_wait_for_edma_empty_idle(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ const u32 empty_idle = (EDMA_STATUS_CACHE_EMPTY | EDMA_STATUS_IDLE);
+ const int per_loop = 5, timeout = (15 * 1000 / per_loop);
+ int i;
+
+ /*
+ * Wait for the EDMA engine to finish transactions in progress.
+ * No idea what a good "timeout" value might be, but measurements
+ * indicate that it often requires hundreds of microseconds
+ * with two drives in-use. So we use the 15msec value above
+ * as a rough guess at what even more drives might require.
+ */
+ for (i = 0; i < timeout; ++i) {
+ u32 edma_stat = readl(port_mmio + EDMA_STATUS_OFS);
+ if ((edma_stat & empty_idle) == empty_idle)
+ break;
+ udelay(per_loop);
+ }
+ /* ata_port_printk(ap, KERN_INFO, "%s: %u+ usecs\n", __func__, i); */
+}
+
/**
* mv_stop_edma_engine - Disable eDMA engine
* @port_mmio: io base address
@@ -906,6 +950,7 @@ static int mv_stop_edma(struct ata_port *ap)
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
return 0;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ mv_wait_for_edma_empty_idle(ap);
if (mv_stop_edma_engine(port_mmio)) {
ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
return -EIO;
@@ -1056,26 +1101,95 @@ static void mv6_dev_config(struct ata_device *adev)
}
}
-static void mv_config_fbs(void __iomem *port_mmio, int enable_fbs)
+static int mv_qc_defer(struct ata_queued_cmd *qc)
{
- u32 old_fcfg, new_fcfg, old_ltmode, new_ltmode;
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ struct mv_port_priv *pp = ap->private_data;
+
/*
- * Various bit settings required for operation
- * in FIS-based switching (fbs) mode on GenIIe:
+ * Don't allow new commands if we're in a delayed EH state
+ * for NCQ and/or FIS-based switching.
*/
- old_fcfg = readl(port_mmio + FIS_CFG_OFS);
- old_ltmode = readl(port_mmio + LTMODE_OFS);
- if (enable_fbs) {
- new_fcfg = old_fcfg | FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode | LTMODE_BIT8;
- } else { /* disable fbs */
- new_fcfg = old_fcfg & ~FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode & ~LTMODE_BIT8;
- }
- if (new_fcfg != old_fcfg)
- writelfl(new_fcfg, port_mmio + FIS_CFG_OFS);
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ return ATA_DEFER_PORT;
+ /*
+ * If the port is completely idle, then allow the new qc.
+ */
+ if (ap->nr_active_links == 0)
+ return 0;
+
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+ /*
+ * The port is operating in host queuing mode (EDMA).
+ * It can accomodate a new qc if the qc protocol
+ * is compatible with the current host queue mode.
+ */
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * The host queue (EDMA) is in NCQ mode.
+ * If the new qc is also an NCQ command,
+ * then allow the new qc.
+ */
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ return 0;
+ } else {
+ /*
+ * The host queue (EDMA) is in non-NCQ, DMA mode.
+ * If the new qc is also a non-NCQ, DMA command,
+ * then allow the new qc.
+ */
+ if (qc->tf.protocol == ATA_PROT_DMA)
+ return 0;
+ }
+ }
+ return ATA_DEFER_PORT;
+}
+
+static void mv_config_fbs(void __iomem *port_mmio, int want_ncq, int want_fbs)
+{
+ u32 new_fiscfg, old_fiscfg;
+ u32 new_ltmode, old_ltmode;
+ u32 new_haltcond, old_haltcond;
+
+ old_fiscfg = readl(port_mmio + FISCFG_OFS);
+ old_ltmode = readl(port_mmio + LTMODE_OFS);
+ old_haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+
+ new_fiscfg = old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
+ new_ltmode = old_ltmode & ~LTMODE_BIT8;
+ new_haltcond = old_haltcond | EDMA_ERR_DEV;
+
+ if (want_fbs) {
+ new_fiscfg = old_fiscfg | FISCFG_SINGLE_SYNC;
+ new_ltmode = old_ltmode | LTMODE_BIT8;
+ if (want_ncq)
+ new_haltcond &= ~EDMA_ERR_DEV;
+ else
+ new_fiscfg |= FISCFG_WAIT_DEV_ERR;
+ }
+
+ if (new_fiscfg != old_fiscfg)
+ writelfl(new_fiscfg, port_mmio + FISCFG_OFS);
if (new_ltmode != old_ltmode)
writelfl(new_ltmode, port_mmio + LTMODE_OFS);
+ if (new_haltcond != old_haltcond)
+ writelfl(new_haltcond, port_mmio + EDMA_HALTCOND_OFS);
+}
+
+static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ u32 old, new;
+
+ /* workaround for 88SX60x1 FEr SATA#25 (part 1) */
+ old = readl(hpriv->base + MV_GPIO_PORT_CTL_OFS);
+ if (want_ncq)
+ new = old | (1 << 22);
+ else
+ new = old & ~(1 << 22);
+ if (new != old)
+ writel(new, hpriv->base + MV_GPIO_PORT_CTL_OFS);
}
static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
@@ -1087,25 +1201,40 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
/* set up non-NCQ EDMA configuration */
cfg = EDMA_CFG_Q_DEPTH; /* always 0x1f for *all* chips */
+ pp->pp_flags &= ~MV_PP_FLAG_FBS_EN;
if (IS_GEN_I(hpriv))
cfg |= (1 << 8); /* enab config burst size mask */
- else if (IS_GEN_II(hpriv))
+ else if (IS_GEN_II(hpriv)) {
cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+ mv_60x1_errata_sata25(ap, want_ncq);
- else if (IS_GEN_IIE(hpriv)) {
- cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
- cfg |= (1 << 22); /* enab 4-entry host queue cache */
- cfg |= (1 << 18); /* enab early completion */
- cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
+ } else if (IS_GEN_IIE(hpriv)) {
+ int want_fbs = sata_pmp_attached(ap);
+ /*
+ * Possible future enhancement:
+ *
+ * The chip can use FBS with non-NCQ, if we allow it,
+ * But first we need to have the error handling in place
+ * for this mode (datasheet section 7.3.15.4.2.3).
+ * So disallow non-NCQ FBS for now.
+ */
+ want_fbs &= want_ncq;
+
+ mv_config_fbs(port_mmio, want_ncq, want_fbs);
- if (want_ncq && sata_pmp_attached(ap)) {
+ if (want_fbs) {
+ pp->pp_flags |= MV_PP_FLAG_FBS_EN;
cfg |= EDMA_CFG_EDMA_FBS; /* FIS-based switching */
- mv_config_fbs(port_mmio, 1);
- } else {
- mv_config_fbs(port_mmio, 0);
}
+
+ cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
+ cfg |= (1 << 22); /* enab 4-entry host queue cache */
+ if (HAS_PCI(ap->host))
+ cfg |= (1 << 18); /* enab early completion */
+ if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
+ cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
}
if (want_ncq) {
@@ -1482,25 +1611,186 @@ static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
return qc;
}
-static void mv_unexpected_intr(struct ata_port *ap)
+static void mv_pmp_error_handler(struct ata_port *ap)
{
+ unsigned int pmp, pmp_map;
struct mv_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->link.eh_info;
- char *when = "";
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH) {
+ /*
+ * Perform NCQ error analysis on failed PMPs
+ * before we freeze the port entirely.
+ *
+ * The failed PMPs are marked earlier by mv_pmp_eh_prep().
+ */
+ pmp_map = pp->delayed_eh_pmp_map;
+ pp->pp_flags &= ~MV_PP_FLAG_DELAYED_EH;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+ pmp_map &= ~this_pmp;
+ ata_eh_analyze_ncq_error(link);
+ }
+ }
+ ata_port_freeze(ap);
+ }
+ sata_pmp_error_handler(ap);
+}
+
+static unsigned int mv_get_err_pmp_map(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+
+ return readl(port_mmio + SATA_TESTCTL_OFS) >> 16;
+}
+
+static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map)
+{
+ struct ata_eh_info *ehi;
+ unsigned int pmp;
+
+ /*
+ * Initialize EH info for PMPs which saw device errors
+ */
+ ehi = &ap->link.eh_info;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+
+ pmp_map &= ~this_pmp;
+ ehi = &link->eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "dev err");
+ ehi->err_mask |= AC_ERR_DEV;
+ ehi->action |= ATA_EH_RESET;
+ ata_link_abort(link);
+ }
+ }
+}
+
+static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ int failed_links;
+ unsigned int old_map, new_map;
+
+ /*
+ * Device error during FBS+NCQ operation:
+ *
+ * Set a port flag to prevent further I/O being enqueued.
+ * Leave the EDMA running to drain outstanding commands from this port.
+ * Perform the post-mortem/EH only when all responses are complete.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.2).
+ */
+ if (!(pp->pp_flags & MV_PP_FLAG_DELAYED_EH)) {
+ pp->pp_flags |= MV_PP_FLAG_DELAYED_EH;
+ pp->delayed_eh_pmp_map = 0;
+ }
+ old_map = pp->delayed_eh_pmp_map;
+ new_map = old_map | mv_get_err_pmp_map(ap);
+
+ if (old_map != new_map) {
+ pp->delayed_eh_pmp_map = new_map;
+ mv_pmp_eh_prep(ap, new_map & ~old_map);
+ }
+ failed_links = hweight16(new_map);
+
+ ata_port_printk(ap, KERN_INFO, "%s: pmp_map=%04x qc_map=%04x "
+ "failed_links=%d nr_active_links=%d\n",
+ __func__, pp->delayed_eh_pmp_map,
+ ap->qc_active, failed_links,
+ ap->nr_active_links);
+
+ if (ap->nr_active_links <= failed_links) {
+ mv_process_crpb_entries(ap, pp);
+ mv_stop_edma(ap);
+ mv_eh_freeze(ap);
+ ata_port_printk(ap, KERN_INFO, "%s: done\n", __func__);
+ return 1; /* handled */
+ }
+ ata_port_printk(ap, KERN_INFO, "%s: waiting\n", __func__);
+ return 1; /* handled */
+}
+
+static int mv_handle_fbs_non_ncq_dev_err(struct ata_port *ap)
+{
/*
- * We got a device interrupt from something that
- * was supposed to be using EDMA or polling.
+ * Possible future enhancement:
+ *
+ * FBS+non-NCQ operation is not yet implemented.
+ * See related notes in mv_edma_cfg().
+ *
+ * Device error during FBS+non-NCQ operation:
+ *
+ * We need to snapshot the shadow registers for each failed command.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.3).
*/
+ return 0; /* not handled */
+}
+
+static int mv_handle_dev_err(struct ata_port *ap, u32 edma_err_cause)
+{
+ struct mv_port_priv *pp = ap->private_data;
+
+ if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
+ return 0; /* EDMA was not active: not handled */
+ if (!(pp->pp_flags & MV_PP_FLAG_FBS_EN))
+ return 0; /* FBS was not active: not handled */
+
+ if (!(edma_err_cause & EDMA_ERR_DEV))
+ return 0; /* non DEV error: not handled */
+ edma_err_cause &= ~EDMA_ERR_IRQ_TRANSIENT;
+ if (edma_err_cause & ~(EDMA_ERR_DEV | EDMA_ERR_SELF_DIS))
+ return 0; /* other problems: not handled */
+
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * EDMA should NOT have self-disabled for this case.
+ * If it did, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (edma_err_cause & EDMA_ERR_SELF_DIS) {
+ ata_port_printk(ap, KERN_WARNING,
+ "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_ncq_dev_err(ap);
+ } else {
+ /*
+ * EDMA should have self-disabled for this case.
+ * If it did not, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (!(edma_err_cause & EDMA_ERR_SELF_DIS)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_non_ncq_dev_err(ap);
+ }
+ return 0; /* not handled */
+}
+
+static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ char *when = "idle";
+
ata_ehi_clear_desc(ehi);
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- when = " while EDMA enabled";
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ when = "disabled";
+ } else if (edma_was_enabled) {
+ when = "EDMA enabled";
} else {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
- when = " while polling";
+ when = "polling";
}
- ata_ehi_push_desc(ehi, "unexpected device interrupt%s", when);
+ ata_ehi_push_desc(ehi, "unexpected device interrupt while %s", when);
ehi->err_mask |= AC_ERR_OTHER;
ehi->action |= ATA_EH_RESET;
ata_port_freeze(ap);
@@ -1518,7 +1808,7 @@ static void mv_unexpected_intr(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+static void mv_err_intr(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, eh_freeze_mask, serr = 0;
@@ -1526,24 +1816,42 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int action = 0, err_mask = 0;
struct ata_eh_info *ehi = &ap->link.eh_info;
-
- ata_ehi_clear_desc(ehi);
+ struct ata_queued_cmd *qc;
+ int abort = 0;
/*
- * Read and clear the err_cause bits. This won't actually
- * clear for some errors (eg. SError), but we will be doing
- * a hard reset in those cases regardless, which *will* clear it.
+ * Read and clear the SError and err_cause bits.
*/
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
+
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- ata_ehi_push_desc(ehi, "edma_err_cause=%08x", edma_err_cause);
+ ata_port_printk(ap, KERN_INFO, "%s: err_cause=%08x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+
+ if (edma_err_cause & EDMA_ERR_DEV) {
+ /*
+ * Device errors during FIS-based switching operation
+ * require special handling.
+ */
+ if (mv_handle_dev_err(ap, edma_err_cause))
+ return;
+ }
+ qc = mv_get_active_qc(ap);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x",
+ edma_err_cause, pp->pp_flags);
/*
* All generations share these EDMA error cause bits:
*/
- if (edma_err_cause & EDMA_ERR_DEV)
+ if (edma_err_cause & EDMA_ERR_DEV) {
err_mask |= AC_ERR_DEV;
+ action |= ATA_EH_RESET;
+ ata_ehi_push_desc(ehi, "dev error");
+ }
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR)) {
@@ -1575,13 +1883,6 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
if (edma_err_cause & EDMA_ERR_SERR) {
- /*
- * Ensure that we read our own SCR, not a pmp link SCR:
- */
- ap->ops->scr_read(ap, SCR_ERROR, &serr);
- /*
- * Don't clear SError here; leave it for libata-eh:
- */
ata_ehi_push_desc(ehi, "SError=%08x", serr);
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
@@ -1601,10 +1902,29 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
else
ehi->err_mask |= err_mask;
- if (edma_err_cause & eh_freeze_mask)
+ if (err_mask == AC_ERR_DEV) {
+ /*
+ * Cannot do ata_port_freeze() here,
+ * because it would kill PIO access,
+ * which is needed for further diagnosis.
+ */
+ mv_eh_freeze(ap);
+ abort = 1;
+ } else if (edma_err_cause & eh_freeze_mask) {
+ /*
+ * Note to self: ata_port_freeze() calls ata_port_abort()
+ */
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ } else {
+ abort = 1;
+ }
+
+ if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void mv_process_crpb_response(struct ata_port *ap,
@@ -1631,8 +1951,9 @@ static void mv_process_crpb_response(struct ata_port *ap,
}
}
ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
- qc->err_mask |= ac_err_mask(ata_status);
- ata_qc_complete(qc);
+ if (!ac_err_mask(ata_status))
+ ata_qc_complete(qc);
+ /* else: leave it for mv_err_intr() */
} else {
ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
__func__, tag);
@@ -1676,77 +1997,107 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
+static void mv_port_intr(struct ata_port *ap, u32 port_cause)
+{
+ struct mv_port_priv *pp;
+ int edma_was_enabled;
+
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ mv_unexpected_intr(ap, 0);
+ return;
+ }
+ /*
+ * Grab a snapshot of the EDMA_EN flag setting,
+ * so that we have a consistent view for this port,
+ * even if something we call of our routines changes it.
+ */
+ pp = ap->private_data;
+ edma_was_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
+ /*
+ * Process completed CRPB response(s) before other events.
+ */
+ if (edma_was_enabled && (port_cause & DONE_IRQ)) {
+ mv_process_crpb_entries(ap, pp);
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ mv_handle_fbs_ncq_dev_err(ap);
+ }
+ /*
+ * Handle chip-reported errors, or continue on to handle PIO.
+ */
+ if (unlikely(port_cause & ERR_IRQ)) {
+ mv_err_intr(ap);
+ } else if (!edma_was_enabled) {
+ struct ata_queued_cmd *qc = mv_get_active_qc(ap);
+ if (qc)
+ ata_sff_host_intr(ap, qc);
+ else
+ mv_unexpected_intr(ap, edma_was_enabled);
+ }
+}
+
/**
* mv_host_intr - Handle all interrupts on the given host controller
* @host: host specific structure
- * @main_cause: Main interrupt cause register for the chip.
+ * @main_irq_cause: Main interrupt cause register for the chip.
*
* LOCKING:
* Inherited from caller.
*/
-static int mv_host_intr(struct ata_host *host, u32 main_cause)
+static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
{
struct mv_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->base, *hc_mmio = NULL;
- u32 hc_irq_cause = 0;
+ void __iomem *mmio = hpriv->base, *hc_mmio;
unsigned int handled = 0, port;
for (port = 0; port < hpriv->n_ports; port++) {
struct ata_port *ap = host->ports[port];
- struct mv_port_priv *pp;
- unsigned int shift, hardport, port_cause;
- /*
- * When we move to the second hc, flag our cached
- * copies of hc_mmio (and hc_irq_cause) as invalid again.
- */
- if (port == MV_PORTS_PER_HC)
- hc_mmio = NULL;
- /*
- * Do nothing if port is not interrupting or is disabled:
- */
+ unsigned int p, shift, hardport, port_cause;
+
MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
- port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ);
- if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED))
- continue;
/*
- * Each hc within the host has its own hc_irq_cause register.
- * We defer reading it until we know we need it, right now:
- *
- * FIXME later: we don't really need to read this register
- * (some logic changes required below if we go that way),
- * because it doesn't tell us anything new. But we do need
- * to write to it, outside the top of this loop,
- * to reset the interrupt triggers for next time.
+ * Each hc within the host has its own hc_irq_cause register,
+ * where the interrupting ports bits get ack'd.
*/
- if (!hc_mmio) {
+ if (hardport == 0) { /* first port on this hc ? */
+ u32 hc_cause = (main_irq_cause >> shift) & HC0_IRQ_PEND;
+ u32 port_mask, ack_irqs;
+ /*
+ * Skip this entire hc if nothing pending for any ports
+ */
+ if (!hc_cause) {
+ port += MV_PORTS_PER_HC - 1;
+ continue;
+ }
+ /*
+ * We don't need/want to read the hc_irq_cause register,
+ * because doing so hurts performance, and
+ * main_irq_cause already gives us everything we need.
+ *
+ * But we do have to *write* to the hc_irq_cause to ack
+ * the ports that we are handling this time through.
+ *
+ * This requires that we create a bitmap for those
+ * ports which interrupted us, and use that bitmap
+ * to ack (only) those ports via hc_irq_cause.
+ */
+ ack_irqs = 0;
+ for (p = 0; p < MV_PORTS_PER_HC; ++p) {
+ if ((port + p) >= hpriv->n_ports)
+ break;
+ port_mask = (DONE_IRQ | ERR_IRQ) << (p * 2);
+ if (hc_cause & port_mask)
+ ack_irqs |= (DMA_IRQ | DEV_IRQ) << p;
+ }
hc_mmio = mv_hc_base_from_port(mmio, port);
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ writelfl(~ack_irqs, hc_mmio + HC_IRQ_CAUSE_OFS);
handled = 1;
}
/*
- * Process completed CRPB response(s) before other events.
- */
- pp = ap->private_data;
- if (hc_irq_cause & (DMA_IRQ << hardport)) {
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN)
- mv_process_crpb_entries(ap, pp);
- }
- /*
- * Handle chip-reported errors, or continue on to handle PIO.
+ * Handle interrupts signalled for this port:
*/
- if (unlikely(port_cause & ERR_IRQ)) {
- mv_err_intr(ap, mv_get_active_qc(ap));
- } else if (hc_irq_cause & (DEV_IRQ << hardport)) {
- if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
- struct ata_queued_cmd *qc = mv_get_active_qc(ap);
- if (qc) {
- ata_sff_host_intr(ap, qc);
- continue;
- }
- }
- mv_unexpected_intr(ap);
- }
+ port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
+ if (port_cause)
+ mv_port_intr(ap, port_cause);
}
return handled;
}
@@ -1811,20 +2162,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
struct ata_host *host = dev_instance;
struct mv_host_priv *hpriv = host->private_data;
unsigned int handled = 0;
- u32 main_cause, main_mask;
+ u32 main_irq_cause, main_irq_mask;
spin_lock(&host->lock);
- main_cause = readl(hpriv->main_cause_reg_addr);
- main_mask = readl(hpriv->main_mask_reg_addr);
+ main_irq_cause = readl(hpriv->main_irq_cause_addr);
+ main_irq_mask = readl(hpriv->main_irq_mask_addr);
/*
* Deal with cases where we either have nothing pending, or have read
* a bogus register value which can indicate HW removal or PCI fault.
*/
- if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) {
- if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host)))
+ if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) {
+ if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host)))
handled = mv_pci_error(host, hpriv->base);
else
- handled = mv_host_intr(host, main_cause);
+ handled = mv_host_intr(host, main_irq_cause);
}
spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
@@ -1893,7 +2244,7 @@ static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x0fcfffff, mmio + MV_FLASH_CTL);
+ writel(0x0fcfffff, mmio + MV_FLASH_CTL_OFS);
}
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
@@ -1912,7 +2263,7 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
u32 tmp;
- writel(0, mmio + MV_GPIO_PORT_CTL);
+ writel(0, mmio + MV_GPIO_PORT_CTL_OFS);
/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
@@ -1930,14 +2281,14 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
if (fix_apm_sq) {
- tmp = readl(phy_mmio + MV5_LT_MODE);
+ tmp = readl(phy_mmio + MV5_LTMODE_OFS);
tmp |= (1 << 19);
- writel(tmp, phy_mmio + MV5_LT_MODE);
+ writel(tmp, phy_mmio + MV5_LTMODE_OFS);
- tmp = readl(phy_mmio + MV5_PHY_CTL);
+ tmp = readl(phy_mmio + MV5_PHY_CTL_OFS);
tmp &= ~0x3;
tmp |= 0x1;
- writel(tmp, phy_mmio + MV5_PHY_CTL);
+ writel(tmp, phy_mmio + MV5_PHY_CTL_OFS);
}
tmp = readl(phy_mmio + MV5_PHY_MODE);
@@ -1955,11 +2306,6 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
@@ -1974,7 +2320,7 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT_OFS);
}
#undef ZERO
@@ -2020,14 +2366,14 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
struct mv_host_priv *hpriv = host->private_data;
u32 tmp;
- tmp = readl(mmio + MV_PCI_MODE);
+ tmp = readl(mmio + MV_PCI_MODE_OFS);
tmp &= 0xff00ffff;
- writel(tmp, mmio + MV_PCI_MODE);
+ writel(tmp, mmio + MV_PCI_MODE_OFS);
ZERO(MV_PCI_DISC_TIMER);
ZERO(MV_PCI_MSI_TRIGGER);
- writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
- ZERO(HC_MAIN_IRQ_MASK_OFS);
+ writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT_OFS);
+ ZERO(PCI_HC_MAIN_IRQ_MASK_OFS);
ZERO(MV_PCI_SERR_MASK);
ZERO(hpriv->irq_cause_ofs);
ZERO(hpriv->irq_mask_ofs);
@@ -2044,10 +2390,10 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
mv5_reset_flash(hpriv, mmio);
- tmp = readl(mmio + MV_GPIO_PORT_CTL);
+ tmp = readl(mmio + MV_GPIO_PORT_CTL_OFS);
tmp &= 0x3;
tmp |= (1 << 5) | (1 << 6);
- writel(tmp, mmio + MV_GPIO_PORT_CTL);
+ writel(tmp, mmio + MV_GPIO_PORT_CTL_OFS);
}
/**
@@ -2120,7 +2466,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
void __iomem *port_mmio;
u32 tmp;
- tmp = readl(mmio + MV_RESET_CFG);
+ tmp = readl(mmio + MV_RESET_CFG_OFS);
if ((tmp & (1 << 0)) == 0) {
hpriv->signal[idx].amps = 0x7 << 8;
hpriv->signal[idx].pre = 0x1 << 5;
@@ -2136,7 +2482,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
+ writel(0x00000060, mmio + MV_GPIO_PORT_CTL_OFS);
}
static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -2234,11 +2580,6 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
@@ -2253,7 +2594,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT_OFS);
}
#undef ZERO
@@ -2296,38 +2637,39 @@ static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
return;
}
-static void mv_setup_ifctl(void __iomem *port_mmio, int want_gen2i)
+static void mv_setup_ifcfg(void __iomem *port_mmio, int want_gen2i)
{
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CFG);
+ u32 ifcfg = readl(port_mmio + SATA_INTERFACE_CFG_OFS);
- ifctl = (ifctl & 0xf7f) | 0x9b1000; /* from chip spec */
+ ifcfg = (ifcfg & 0xf7f) | 0x9b1000; /* from chip spec */
if (want_gen2i)
- ifctl |= (1 << 7); /* enable gen2i speed */
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CFG);
+ ifcfg |= (1 << 7); /* enable gen2i speed */
+ writelfl(ifcfg, port_mmio + SATA_INTERFACE_CFG_OFS);
}
-/*
- * Caller must ensure that EDMA is not active,
- * by first doing mv_stop_edma() where needed.
- */
static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no)
{
void __iomem *port_mmio = mv_port_base(mmio, port_no);
+ /*
+ * The datasheet warns against setting EDMA_RESET when EDMA is active
+ * (but doesn't say what the problem might be). So we first try
+ * to disable the EDMA engine before doing the EDMA_RESET operation.
+ */
mv_stop_edma_engine(port_mmio);
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD_OFS);
if (!IS_GEN_I(hpriv)) {
- /* Enable 3.0gb/s link speed */
- mv_setup_ifctl(port_mmio, 1);
+ /* Enable 3.0gb/s link speed: this survives EDMA_RESET */
+ mv_setup_ifcfg(port_mmio, 1);
}
/*
- * Strobing ATA_RST here causes a hard reset of the SATA transport,
+ * Strobing EDMA_RESET here causes a hard reset of the SATA transport,
* link, and physical layers. It resets all SATA interface registers
* (except for SATA_INTERFACE_CFG), and issues a COMRESET to the dev.
*/
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD_OFS);
udelay(25); /* allow reset propagation */
writelfl(0, port_mmio + EDMA_CMD_OFS);
@@ -2391,7 +2733,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
sata_scr_read(link, SCR_STATUS, &sstatus);
if (!IS_GEN_I(hpriv) && ++attempts >= 5 && sstatus == 0x121) {
/* Force 1.5gb/s link speed and try again */
- mv_setup_ifctl(mv_ap_base(ap), 0);
+ mv_setup_ifcfg(mv_ap_base(ap), 0);
if (time_after(jiffies + HZ, deadline))
extra = HZ; /* only extend it once, max */
}
@@ -2404,7 +2746,7 @@ static void mv_eh_freeze(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int shift, hardport, port = ap->port_no;
- u32 main_mask;
+ u32 main_irq_mask;
/* FIXME: handle coalescing completion events properly */
@@ -2412,9 +2754,9 @@ static void mv_eh_freeze(struct ata_port *ap)
MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
/* disable assertion of portN err, done events */
- main_mask = readl(hpriv->main_mask_reg_addr);
- main_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_mask, hpriv->main_mask_reg_addr);
+ main_irq_mask = readl(hpriv->main_irq_mask_addr);
+ main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
+ writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
}
static void mv_eh_thaw(struct ata_port *ap)
@@ -2423,7 +2765,7 @@ static void mv_eh_thaw(struct ata_port *ap)
unsigned int shift, hardport, port = ap->port_no;
void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port);
void __iomem *port_mmio = mv_ap_base(ap);
- u32 main_mask, hc_irq_cause;
+ u32 main_irq_mask, hc_irq_cause;
/* FIXME: handle coalescing completion events properly */
@@ -2438,9 +2780,9 @@ static void mv_eh_thaw(struct ata_port *ap)
writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
/* enable assertion of portN err, done events */
- main_mask = readl(hpriv->main_mask_reg_addr);
- main_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_mask, hpriv->main_mask_reg_addr);
+ main_irq_mask = readl(hpriv->main_irq_mask_addr);
+ main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
+ writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
}
/**
@@ -2492,6 +2834,34 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
}
+static unsigned int mv_in_pcix_mode(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (!HAS_PCI(host) || !IS_PCIE(hpriv))
+ return 0; /* not PCI-X capable */
+ reg = readl(mmio + MV_PCI_MODE_OFS);
+ if ((reg & MV_PCI_MODE_MASK) == 0)
+ return 0; /* conventional PCI mode */
+ return 1; /* chip is in PCI-X mode */
+}
+
+static int mv_pci_cut_through_okay(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (!mv_in_pcix_mode(host)) {
+ reg = readl(mmio + PCI_COMMAND_OFS);
+ if (reg & PCI_COMMAND_MRDTRIG)
+ return 0; /* not okay */
+ }
+ return 1; /* okay */
+}
+
static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
@@ -2559,7 +2929,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break;
case chip_7042:
- hp_flags |= MV_HP_PCIE;
+ hp_flags |= MV_HP_PCIE | MV_HP_CUT_THROUGH;
if (pdev->vendor == PCI_VENDOR_ID_TTI &&
(pdev->device == 0x2300 || pdev->device == 0x2310))
{
@@ -2589,9 +2959,12 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
" and avoid the final two gigabytes on"
" all RocketRAID BIOS initialized drives.\n");
}
+ /* drop through */
case chip_6042:
hpriv->ops = &mv6xxx_ops;
hp_flags |= MV_HP_GEN_IIE;
+ if (board_idx == chip_6042 && mv_pci_cut_through_okay(host))
+ hp_flags |= MV_HP_CUT_THROUGH;
switch (pdev->revision) {
case 0x0:
@@ -2654,15 +3027,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
goto done;
if (HAS_PCI(host)) {
- hpriv->main_cause_reg_addr = mmio + HC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = mmio + HC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS;
} else {
- hpriv->main_cause_reg_addr = mmio + HC_SOC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = mmio + HC_SOC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS;
}
/* global interrupt mask: 0 == mask everything */
- writel(0, hpriv->main_mask_reg_addr);
+ writel(0, hpriv->main_irq_mask_addr);
n_hc = mv_get_hc_count(host->ports[0]->flags);
@@ -2712,23 +3085,23 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
if (IS_GEN_I(hpriv))
writelfl(~HC_MAIN_MASKED_IRQS_5,
- hpriv->main_mask_reg_addr);
+ hpriv->main_irq_mask_addr);
else
writelfl(~HC_MAIN_MASKED_IRQS,
- hpriv->main_mask_reg_addr);
+ hpriv->main_irq_mask_addr);
VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
"PCI int cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_cause_reg_addr),
- readl(hpriv->main_mask_reg_addr),
+ readl(hpriv->main_irq_cause_addr),
+ readl(hpriv->main_irq_mask_addr),
readl(mmio + hpriv->irq_cause_ofs),
readl(mmio + hpriv->irq_mask_ofs));
} else {
writelfl(~HC_MAIN_MASKED_IRQS_SOC,
- hpriv->main_mask_reg_addr);
+ hpriv->main_irq_mask_addr);
VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_cause_reg_addr),
- readl(hpriv->main_mask_reg_addr));
+ readl(hpriv->main_irq_cause_addr),
+ readl(hpriv->main_irq_mask_addr));
}
done:
return rc;
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 5aa12b011a9a..6adb72a2f876 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/poison.h>
#include <linux/bitrev.h>
+#include <linux/mutex.h>
#include <asm/atomic.h>
#include <asm/io.h>
@@ -1177,7 +1178,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
vcc->tx_frame_bits = tx_frame_bits;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer on the channel already, just modify rate...
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@@ -1203,7 +1204,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
schedule();
}
dev->txer[vci].tx_present = 1;
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
if (rxtp->traffic_class != ATM_NONE) {
@@ -1211,7 +1212,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
vcc->rx_info.pool = pool;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
/* grow RX buffer pool */
if (!dev->rxq[pool].buffers_wanted)
dev->rxq[pool].buffers_wanted = rx_lats;
@@ -1237,7 +1238,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
schedule();
// this link allows RX frames through
dev->rxer[vci] = atm_vcc;
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// indicate readiness
@@ -1262,7 +1263,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
command cmd;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer still on the channel, just modify rate... XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@@ -1277,7 +1278,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
dev->txer[vci].tx_present = 0;
while (command_do (dev, &cmd))
schedule();
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// disable RXing
@@ -1287,7 +1288,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
// this is (the?) one reason why we need the amb_vcc struct
unsigned char pool = vcc->rx_info.pool;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->txer[vci].tx_present) {
// TXer still on the channel, just go to pool zero XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
@@ -1314,7 +1315,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
dev->rxq[pool].buffers_wanted = 0;
drain_rx_pool (dev, pool);
}
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// free our structure
@@ -2188,7 +2189,7 @@ static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev)
// semaphore for txer/rxer modifications - we cannot use a
// spinlock as the critical region needs to switch processes
- init_MUTEX (&dev->vcc_sf);
+ mutex_init(&dev->vcc_sf);
// queue manipulation spinlocks; we want atomic reads and
// writes to the queue descriptors (handles IRQ and SMP)
// consider replacing "int pending" -> "atomic_t available"
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index ff2a303cbe00..df55fa8387dc 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -638,7 +638,7 @@ struct amb_dev {
amb_txq txq;
amb_rxq rxq[NUM_RX_POOLS];
- struct semaphore vcc_sf;
+ struct mutex vcc_sf;
amb_tx_info txer[NUM_VCS];
struct atm_vcc * rxer[NUM_VCS];
unsigned int tx_avail;
diff --git a/drivers/base/base.h b/drivers/base/base.h
index c0444146c09a..2c9ae43e2219 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -64,17 +64,6 @@ extern void sysdev_shutdown(void);
extern int sysdev_suspend(pm_message_t state);
extern int sysdev_resume(void);
-static inline struct class_device *to_class_dev(struct kobject *obj)
-{
- return container_of(obj, struct class_device, kobj);
-}
-
-static inline
-struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
-{
- return container_of(_attr, struct class_device_attribute, attr);
-}
-
extern char *make_class_name(const char *name, struct kobject *kobj);
extern int devres_release_all(struct device *dev);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index b4901799308b..e085af0ff94f 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -140,7 +140,6 @@ int class_register(struct class *cls)
pr_debug("device class '%s': registering\n", cls->name);
- INIT_LIST_HEAD(&cls->children);
INIT_LIST_HEAD(&cls->devices);
INIT_LIST_HEAD(&cls->interfaces);
kset_init(&cls->class_dirs);
@@ -179,27 +178,13 @@ static void class_create_release(struct class *cls)
kfree(cls);
}
-static void class_device_create_release(struct class_device *class_dev)
-{
- pr_debug("%s called for %s\n", __func__, class_dev->class_id);
- kfree(class_dev);
-}
-
-/* needed to allow these devices to have parent class devices */
-static int class_device_create_uevent(struct class_device *class_dev,
- struct kobj_uevent_env *env)
-{
- pr_debug("%s called for %s\n", __func__, class_dev->class_id);
- return 0;
-}
-
/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
* @name: pointer to a string for the name of this class.
*
* This is used to create a struct class pointer that can then be used
- * in calls to class_device_create().
+ * in calls to device_create().
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
@@ -218,7 +203,6 @@ struct class *class_create(struct module *owner, const char *name)
cls->name = name;
cls->owner = owner;
cls->class_release = class_create_release;
- cls->release = class_device_create_release;
retval = class_register(cls);
if (retval)
@@ -246,113 +230,6 @@ void class_destroy(struct class *cls)
class_unregister(cls);
}
-/* Class Device Stuff */
-
-int class_device_create_file(struct class_device *class_dev,
- const struct class_device_attribute *attr)
-{
- int error = -EINVAL;
- if (class_dev)
- error = sysfs_create_file(&class_dev->kobj, &attr->attr);
- return error;
-}
-
-void class_device_remove_file(struct class_device *class_dev,
- const struct class_device_attribute *attr)
-{
- if (class_dev)
- sysfs_remove_file(&class_dev->kobj, &attr->attr);
-}
-
-int class_device_create_bin_file(struct class_device *class_dev,
- struct bin_attribute *attr)
-{
- int error = -EINVAL;
- if (class_dev)
- error = sysfs_create_bin_file(&class_dev->kobj, attr);
- return error;
-}
-
-void class_device_remove_bin_file(struct class_device *class_dev,
- struct bin_attribute *attr)
-{
- if (class_dev)
- sysfs_remove_bin_file(&class_dev->kobj, attr);
-}
-
-static ssize_t class_device_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
- struct class_device *cd = to_class_dev(kobj);
- ssize_t ret = 0;
-
- if (class_dev_attr->show)
- ret = class_dev_attr->show(cd, buf);
- return ret;
-}
-
-static ssize_t class_device_attr_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
- struct class_device *cd = to_class_dev(kobj);
- ssize_t ret = 0;
-
- if (class_dev_attr->store)
- ret = class_dev_attr->store(cd, buf, count);
- return ret;
-}
-
-static struct sysfs_ops class_dev_sysfs_ops = {
- .show = class_device_attr_show,
- .store = class_device_attr_store,
-};
-
-static void class_dev_release(struct kobject *kobj)
-{
- struct class_device *cd = to_class_dev(kobj);
- struct class *cls = cd->class;
-
- pr_debug("device class '%s': release.\n", cd->class_id);
-
- if (cd->release)
- cd->release(cd);
- else if (cls->release)
- cls->release(cd);
- else {
- printk(KERN_ERR "Class Device '%s' does not have a release() "
- "function, it is broken and must be fixed.\n",
- cd->class_id);
- WARN_ON(1);
- }
-}
-
-static struct kobj_type class_device_ktype = {
- .sysfs_ops = &class_dev_sysfs_ops,
- .release = class_dev_release,
-};
-
-static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
-{
- struct kobj_type *ktype = get_ktype(kobj);
-
- if (ktype == &class_device_ktype) {
- struct class_device *class_dev = to_class_dev(kobj);
- if (class_dev->class)
- return 1;
- }
- return 0;
-}
-
-static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
-{
- struct class_device *class_dev = to_class_dev(kobj);
-
- return class_dev->class->name;
-}
-
#ifdef CONFIG_SYSFS_DEPRECATED
char *make_class_name(const char *name, struct kobject *kobj)
{
@@ -370,445 +247,8 @@ char *make_class_name(const char *name, struct kobject *kobj)
strcat(class_name, kobject_name(kobj));
return class_name;
}
-
-static int make_deprecated_class_device_links(struct class_device *class_dev)
-{
- char *class_name;
- int error;
-
- if (!class_dev->dev)
- return 0;
-
- class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- if (class_name)
- error = sysfs_create_link(&class_dev->dev->kobj,
- &class_dev->kobj, class_name);
- else
- error = -ENOMEM;
- kfree(class_name);
- return error;
-}
-
-static void remove_deprecated_class_device_links(struct class_device *class_dev)
-{
- char *class_name;
-
- if (!class_dev->dev)
- return;
-
- class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- if (class_name)
- sysfs_remove_link(&class_dev->dev->kobj, class_name);
- kfree(class_name);
-}
-#else
-static inline int make_deprecated_class_device_links(struct class_device *cd)
-{ return 0; }
-static void remove_deprecated_class_device_links(struct class_device *cd)
-{ }
#endif
-static int class_uevent(struct kset *kset, struct kobject *kobj,
- struct kobj_uevent_env *env)
-{
- struct class_device *class_dev = to_class_dev(kobj);
- struct device *dev = class_dev->dev;
- int retval = 0;
-
- pr_debug("%s - name = %s\n", __func__, class_dev->class_id);
-
- if (MAJOR(class_dev->devt)) {
- add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
-
- add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
- }
-
- if (dev) {
- const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
- if (path) {
- add_uevent_var(env, "PHYSDEVPATH=%s", path);
- kfree(path);
- }
-
- if (dev->bus)
- add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
-
- if (dev->driver)
- add_uevent_var(env, "PHYSDEVDRIVER=%s",
- dev->driver->name);
- }
-
- if (class_dev->uevent) {
- /* have the class device specific function add its stuff */
- retval = class_dev->uevent(class_dev, env);
- if (retval)
- pr_debug("class_dev->uevent() returned %d\n", retval);
- } else if (class_dev->class->uevent) {
- /* have the class specific function add its stuff */
- retval = class_dev->class->uevent(class_dev, env);
- if (retval)
- pr_debug("class->uevent() returned %d\n", retval);
- }
-
- return retval;
-}
-
-static struct kset_uevent_ops class_uevent_ops = {
- .filter = class_uevent_filter,
- .name = class_uevent_name,
- .uevent = class_uevent,
-};
-
-/*
- * DO NOT copy how this is created, kset_create_and_add() should be
- * called, but this is a hold-over from the old-way and will be deleted
- * entirely soon.
- */
-static struct kset class_obj_subsys = {
- .uevent_ops = &class_uevent_ops,
-};
-
-static int class_device_add_attrs(struct class_device *cd)
-{
- int i;
- int error = 0;
- struct class *cls = cd->class;
-
- if (cls->class_dev_attrs) {
- for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
- error = class_device_create_file(cd,
- &cls->class_dev_attrs[i]);
- if (error)
- goto err;
- }
- }
-done:
- return error;
-err:
- while (--i >= 0)
- class_device_remove_file(cd, &cls->class_dev_attrs[i]);
- goto done;
-}
-
-static void class_device_remove_attrs(struct class_device *cd)
-{
- int i;
- struct class *cls = cd->class;
-
- if (cls->class_dev_attrs) {
- for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
- class_device_remove_file(cd, &cls->class_dev_attrs[i]);
- }
-}
-
-static int class_device_add_groups(struct class_device *cd)
-{
- int i;
- int error = 0;
-
- if (cd->groups) {
- for (i = 0; cd->groups[i]; i++) {
- error = sysfs_create_group(&cd->kobj, cd->groups[i]);
- if (error) {
- while (--i >= 0)
- sysfs_remove_group(&cd->kobj,
- cd->groups[i]);
- goto out;
- }
- }
- }
-out:
- return error;
-}
-
-static void class_device_remove_groups(struct class_device *cd)
-{
- int i;
- if (cd->groups)
- for (i = 0; cd->groups[i]; i++)
- sysfs_remove_group(&cd->kobj, cd->groups[i]);
-}
-
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
- return print_dev_t(buf, class_dev->devt);
-}
-
-static struct class_device_attribute class_devt_attr =
- __ATTR(dev, S_IRUGO, show_dev, NULL);
-
-static ssize_t store_uevent(struct class_device *class_dev,
- const char *buf, size_t count)
-{
- kobject_uevent(&class_dev->kobj, KOBJ_ADD);
- return count;
-}
-
-static struct class_device_attribute class_uevent_attr =
- __ATTR(uevent, S_IWUSR, NULL, store_uevent);
-
-void class_device_initialize(struct class_device *class_dev)
-{
- class_dev->kobj.kset = &class_obj_subsys;
- kobject_init(&class_dev->kobj, &class_device_ktype);
- INIT_LIST_HEAD(&class_dev->node);
-}
-
-int class_device_add(struct class_device *class_dev)
-{
- struct class *parent_class = NULL;
- struct class_device *parent_class_dev = NULL;
- struct class_interface *class_intf;
- int error = -EINVAL;
-
- class_dev = class_device_get(class_dev);
- if (!class_dev)
- return -EINVAL;
-
- if (!strlen(class_dev->class_id))
- goto out1;
-
- parent_class = class_get(class_dev->class);
- if (!parent_class)
- goto out1;
-
- parent_class_dev = class_device_get(class_dev->parent);
-
- pr_debug("CLASS: registering class device: ID = '%s'\n",
- class_dev->class_id);
-
- /* first, register with generic layer. */
- if (parent_class_dev)
- class_dev->kobj.parent = &parent_class_dev->kobj;
- else
- class_dev->kobj.parent = &parent_class->subsys.kobj;
-
- error = kobject_add(&class_dev->kobj, class_dev->kobj.parent,
- "%s", class_dev->class_id);
- if (error)
- goto out2;
-
- /* add the needed attributes to this device */
- error = sysfs_create_link(&class_dev->kobj,
- &parent_class->subsys.kobj, "subsystem");
- if (error)
- goto out3;
-
- error = class_device_create_file(class_dev, &class_uevent_attr);
- if (error)
- goto out3;
-
- if (MAJOR(class_dev->devt)) {
- error = class_device_create_file(class_dev, &class_devt_attr);
- if (error)
- goto out4;
- }
-
- error = class_device_add_attrs(class_dev);
- if (error)
- goto out5;
-
- if (class_dev->dev) {
- error = sysfs_create_link(&class_dev->kobj,
- &class_dev->dev->kobj, "device");
- if (error)
- goto out6;
- }
-
- error = class_device_add_groups(class_dev);
- if (error)
- goto out7;
-
- error = make_deprecated_class_device_links(class_dev);
- if (error)
- goto out8;
-
- kobject_uevent(&class_dev->kobj, KOBJ_ADD);
-
- /* notify any interfaces this device is now here */
- down(&parent_class->sem);
- list_add_tail(&class_dev->node, &parent_class->children);
- list_for_each_entry(class_intf, &parent_class->interfaces, node) {
- if (class_intf->add)
- class_intf->add(class_dev, class_intf);
- }
- up(&parent_class->sem);
-
- goto out1;
-
- out8:
- class_device_remove_groups(class_dev);
- out7:
- if (class_dev->dev)
- sysfs_remove_link(&class_dev->kobj, "device");
- out6:
- class_device_remove_attrs(class_dev);
- out5:
- if (MAJOR(class_dev->devt))
- class_device_remove_file(class_dev, &class_devt_attr);
- out4:
- class_device_remove_file(class_dev, &class_uevent_attr);
- out3:
- kobject_del(&class_dev->kobj);
- out2:
- if (parent_class_dev)
- class_device_put(parent_class_dev);
- class_put(parent_class);
- out1:
- class_device_put(class_dev);
- return error;
-}
-
-int class_device_register(struct class_device *class_dev)
-{
- class_device_initialize(class_dev);
- return class_device_add(class_dev);
-}
-
-/**
- * class_device_create - creates a class device and registers it with sysfs
- * @cls: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct class_device of this new device, if
- * any.
- * @devt: the dev_t for the char device to be added.
- * @device: a pointer to a struct device that is assiociated with this class
- * device.
- * @fmt: string for the class device's name
- *
- * This function can be used by char device classes. A struct
- * class_device will be created in sysfs, registered to the specified
- * class.
- * A "dev" file will be created, showing the dev_t for the device, if
- * the dev_t is not 0,0.
- * If a pointer to a parent struct class_device is passed in, the newly
- * created struct class_device will be a child of that device in sysfs.
- * The pointer to the struct class_device will be returned from the
- * call. Any further sysfs files that might be required can be created
- * using this pointer.
- *
- * Note: the struct class passed to this function must have previously
- * been created with a call to class_create().
- */
-struct class_device *class_device_create(struct class *cls,
- struct class_device *parent,
- dev_t devt,
- struct device *device,
- const char *fmt, ...)
-{
- va_list args;
- struct class_device *class_dev = NULL;
- int retval = -ENODEV;
-
- if (cls == NULL || IS_ERR(cls))
- goto error;
-
- class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
- if (!class_dev) {
- retval = -ENOMEM;
- goto error;
- }
-
- class_dev->devt = devt;
- class_dev->dev = device;
- class_dev->class = cls;
- class_dev->parent = parent;
- class_dev->release = class_device_create_release;
- class_dev->uevent = class_device_create_uevent;
-
- va_start(args, fmt);
- vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
- va_end(args);
- retval = class_device_register(class_dev);
- if (retval)
- goto error;
-
- return class_dev;
-
-error:
- kfree(class_dev);
- return ERR_PTR(retval);
-}
-
-void class_device_del(struct class_device *class_dev)
-{
- struct class *parent_class = class_dev->class;
- struct class_device *parent_device = class_dev->parent;
- struct class_interface *class_intf;
-
- if (parent_class) {
- down(&parent_class->sem);
- list_del_init(&class_dev->node);
- list_for_each_entry(class_intf, &parent_class->interfaces, node)
- if (class_intf->remove)
- class_intf->remove(class_dev, class_intf);
- up(&parent_class->sem);
- }
-
- if (class_dev->dev) {
- remove_deprecated_class_device_links(class_dev);
- sysfs_remove_link(&class_dev->kobj, "device");
- }
- sysfs_remove_link(&class_dev->kobj, "subsystem");
- class_device_remove_file(class_dev, &class_uevent_attr);
- if (MAJOR(class_dev->devt))
- class_device_remove_file(class_dev, &class_devt_attr);
- class_device_remove_attrs(class_dev);
- class_device_remove_groups(class_dev);
-
- kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);
- kobject_del(&class_dev->kobj);
-
- class_device_put(parent_device);
- class_put(parent_class);
-}
-
-void class_device_unregister(struct class_device *class_dev)
-{
- pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
- class_dev->class_id);
- class_device_del(class_dev);
- class_device_put(class_dev);
-}
-
-/**
- * class_device_destroy - removes a class device that was created with class_device_create()
- * @cls: the pointer to the struct class that this device was registered * with.
- * @devt: the dev_t of the device that was previously registered.
- *
- * This call unregisters and cleans up a class device that was created with a
- * call to class_device_create()
- */
-void class_device_destroy(struct class *cls, dev_t devt)
-{
- struct class_device *class_dev = NULL;
- struct class_device *class_dev_tmp;
-
- down(&cls->sem);
- list_for_each_entry(class_dev_tmp, &cls->children, node) {
- if (class_dev_tmp->devt == devt) {
- class_dev = class_dev_tmp;
- break;
- }
- }
- up(&cls->sem);
-
- if (class_dev)
- class_device_unregister(class_dev);
-}
-
-struct class_device *class_device_get(struct class_device *class_dev)
-{
- if (class_dev)
- return to_class_dev(kobject_get(&class_dev->kobj));
- return NULL;
-}
-
-void class_device_put(struct class_device *class_dev)
-{
- if (class_dev)
- kobject_put(&class_dev->kobj);
-}
-
/**
* class_for_each_device - device iterator
* @class: the class we're iterating
@@ -897,56 +337,9 @@ struct device *class_find_device(struct class *class, void *data,
}
EXPORT_SYMBOL_GPL(class_find_device);
-/**
- * class_find_child - device iterator for locating a particular class_device
- * @class: the class we're iterating
- * @data: data for the match function
- * @match: function to check class_device
- *
- * This function returns a reference to a class_device that is 'found' for
- * later use, as determined by the @match callback.
- *
- * The callback should return 0 if the class_device doesn't match and non-zero
- * if it does. If the callback returns non-zero, this function will
- * return to the caller and not iterate over any more class_devices.
- *
- * Note, you will need to drop the reference with class_device_put() after use.
- *
- * We hold class->sem in this function, so it can not be
- * re-acquired in @match, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
- */
-struct class_device *class_find_child(struct class *class, void *data,
- int (*match)(struct class_device *, void *))
-{
- struct class_device *dev;
- int found = 0;
-
- if (!class)
- return NULL;
-
- down(&class->sem);
- list_for_each_entry(dev, &class->children, node) {
- dev = class_device_get(dev);
- if (dev) {
- if (match(dev, data)) {
- found = 1;
- break;
- } else
- class_device_put(dev);
- } else
- break;
- }
- up(&class->sem);
-
- return found ? dev : NULL;
-}
-EXPORT_SYMBOL_GPL(class_find_child);
-
int class_interface_register(struct class_interface *class_intf)
{
struct class *parent;
- struct class_device *class_dev;
struct device *dev;
if (!class_intf || !class_intf->class)
@@ -958,10 +351,6 @@ int class_interface_register(struct class_interface *class_intf)
down(&parent->sem);
list_add_tail(&class_intf->node, &parent->interfaces);
- if (class_intf->add) {
- list_for_each_entry(class_dev, &parent->children, node)
- class_intf->add(class_dev, class_intf);
- }
if (class_intf->add_dev) {
list_for_each_entry(dev, &parent->devices, node)
class_intf->add_dev(dev, class_intf);
@@ -974,7 +363,6 @@ int class_interface_register(struct class_interface *class_intf)
void class_interface_unregister(struct class_interface *class_intf)
{
struct class *parent = class_intf->class;
- struct class_device *class_dev;
struct device *dev;
if (!parent)
@@ -982,10 +370,6 @@ void class_interface_unregister(struct class_interface *class_intf)
down(&parent->sem);
list_del_init(&class_intf->node);
- if (class_intf->remove) {
- list_for_each_entry(class_dev, &parent->children, node)
- class_intf->remove(class_dev, class_intf);
- }
if (class_intf->remove_dev) {
list_for_each_entry(dev, &parent->devices, node)
class_intf->remove_dev(dev, class_intf);
@@ -1000,13 +384,6 @@ int __init classes_init(void)
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
-
- /* ick, this is ugly, the things we go through to keep from showing up
- * in sysfs... */
- kset_init(&class_obj_subsys);
- kobject_set_name(&class_obj_subsys.kobj, "class_obj");
- if (!class_obj_subsys.kobj.parent)
- class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
return 0;
}
@@ -1017,19 +394,5 @@ EXPORT_SYMBOL_GPL(class_unregister);
EXPORT_SYMBOL_GPL(class_create);
EXPORT_SYMBOL_GPL(class_destroy);
-EXPORT_SYMBOL_GPL(class_device_register);
-EXPORT_SYMBOL_GPL(class_device_unregister);
-EXPORT_SYMBOL_GPL(class_device_initialize);
-EXPORT_SYMBOL_GPL(class_device_add);
-EXPORT_SYMBOL_GPL(class_device_del);
-EXPORT_SYMBOL_GPL(class_device_get);
-EXPORT_SYMBOL_GPL(class_device_put);
-EXPORT_SYMBOL_GPL(class_device_create);
-EXPORT_SYMBOL_GPL(class_device_destroy);
-EXPORT_SYMBOL_GPL(class_device_create_file);
-EXPORT_SYMBOL_GPL(class_device_remove_file);
-EXPORT_SYMBOL_GPL(class_device_create_bin_file);
-EXPORT_SYMBOL_GPL(class_device_remove_bin_file);
-
EXPORT_SYMBOL_GPL(class_interface_register);
EXPORT_SYMBOL_GPL(class_interface_unregister);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 9248e0927d08..be288b5e4180 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -787,6 +787,10 @@ int device_add(struct device *dev)
parent = get_device(dev->parent);
setup_parent(dev, parent);
+ /* use parent numa_node */
+ if (parent)
+ set_dev_node(dev, dev_to_node(parent));
+
/* first, register with generic layer. */
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
if (error)
@@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent)
dev->parent = new_parent;
if (old_parent)
klist_remove(&dev->knode_parent);
- if (new_parent)
+ if (new_parent) {
klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+ set_dev_node(dev, dev_to_node(new_parent));
+ }
+
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
@@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent)
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
if (new_parent)
klist_remove(&dev->knode_parent);
- if (old_parent)
+ dev->parent = old_parent;
+ if (old_parent) {
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
+ set_dev_node(dev, dev_to_node(old_parent));
+ }
}
cleanup_glue_dir(dev, new_parent_kobj);
put_device(new_parent);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 6fe417429977..e38dfed41d80 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -18,7 +18,7 @@ struct sysdev_class cpu_sysdev_class = {
};
EXPORT_SYMBOL(cpu_sysdev_class);
-static struct sys_device *cpu_sys_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices);
#ifdef CONFIG_HOTPLUG_CPU
static ssize_t show_online(struct sys_device *dev, char *buf)
@@ -68,7 +68,7 @@ void unregister_cpu(struct cpu *cpu)
sysdev_remove_file(&cpu->sysdev, &attr_online);
sysdev_unregister(&cpu->sysdev);
- cpu_sys_devices[logical_cpu] = NULL;
+ per_cpu(cpu_sys_devices, logical_cpu) = NULL;
return;
}
#else /* ... !CONFIG_HOTPLUG_CPU */
@@ -167,7 +167,7 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
if (!error && cpu->hotpluggable)
register_cpu_control(cpu);
if (!error)
- cpu_sys_devices[num] = &cpu->sysdev;
+ per_cpu(cpu_sys_devices, num) = &cpu->sysdev;
if (!error)
register_cpu_under_node(num, cpu_to_node(num));
@@ -180,8 +180,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
struct sys_device *get_cpu_sysdev(unsigned cpu)
{
- if (cpu < NR_CPUS)
- return cpu_sys_devices[cpu];
+ if (cpu < nr_cpu_ids && cpu_possible(cpu))
+ return per_cpu(cpu_sys_devices, cpu);
else
return NULL;
}
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 9a6537f14401..2ef5acf4368b 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -217,12 +217,22 @@ static void driver_remove_groups(struct device_driver *drv,
int driver_register(struct device_driver *drv)
{
int ret;
+ struct device_driver *other;
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
+
+ other = driver_find(drv->name, drv->bus);
+ if (other) {
+ put_driver(other);
+ printk(KERN_ERR "Error: Driver '%s' is already registered, "
+ "aborting...\n", drv->name);
+ return -EEXIST;
+ }
+
ret = bus_add_driver(drv);
if (ret)
return ret;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 1fef7df8c9d6..9fd4a8534146 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -396,6 +396,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
if (!firmware_p)
return -EINVAL;
+ printk(KERN_INFO "firmware: requesting %s\n", name);
+
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 8ce6de5a7e28..937e8258981d 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -53,11 +53,13 @@ int register_memory_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&memory_chain, nb);
}
+EXPORT_SYMBOL(register_memory_notifier);
void unregister_memory_notifier(struct notifier_block *nb)
{
blocking_notifier_chain_unregister(&memory_chain, nb);
}
+EXPORT_SYMBOL(unregister_memory_notifier);
/*
* register_memory - Setup a sysfs device for a memory block
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 12fde2d03d69..39f3d1b3a213 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -77,6 +77,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
"Node %d PageTables: %8lu kB\n"
"Node %d NFS_Unstable: %8lu kB\n"
"Node %d Bounce: %8lu kB\n"
+ "Node %d WritebackTmp: %8lu kB\n"
"Node %d Slab: %8lu kB\n"
"Node %d SReclaimable: %8lu kB\n"
"Node %d SUnreclaim: %8lu kB\n",
@@ -99,6 +100,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
nid, K(node_page_state(nid, NR_PAGETABLE)),
nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
nid, K(node_page_state(nid, NR_BOUNCE)),
+ nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 7b76fd3b93a4..45cc3d9eacb8 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -418,7 +418,7 @@ void __suspend_report_result(const char *function, void *fn, int ret)
{
if (ret) {
printk(KERN_ERR "%s(): ", function);
- print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+ print_fn_descriptor_symbol("%s returns ", fn);
printk("%d\n", ret);
}
}
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 4fbb56bcb1ee..358bb0be3c08 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -175,8 +175,7 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
}
/* Check whether this driver has already been added to a class. */
- if ((drv->entry.next != drv->entry.prev) ||
- (drv->entry.next != NULL)) {
+ if (drv->entry.next && !list_empty(&drv->entry)) {
printk(KERN_WARNING "sysdev: class %s: driver (%p) has already"
" been registered to a class, something is wrong, but "
"will forge on!\n", cls->name, drv);
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index c9751b2b57e6..7516baff3bb9 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1714,10 +1714,10 @@ static int __init amiga_floppy_init(void)
int i, ret;
if (!MACH_IS_AMIGA)
- return -ENXIO;
+ return -ENODEV;
if (!AMIGAHW_PRESENT(AMI_FLOPPY))
- return -ENXIO;
+ return -ENODEV;
if (register_blkdev(FLOPPY_MAJOR,"fd"))
return -EBUSY;
@@ -1755,7 +1755,7 @@ static int __init amiga_floppy_init(void)
if (!floppy_queue)
goto out_queue;
- ret = -ENXIO;
+ ret = -ENODEV;
if (fd_probe_drives() < 1) /* No usable drives */
goto out_probe;
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 280e71ee744c..5b4c6e649c11 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -195,7 +195,6 @@ void aoedev_exit(void);
struct aoedev *aoedev_by_aoeaddr(int maj, int min);
struct aoedev *aoedev_by_sysminor_m(ulong sysminor);
void aoedev_downdev(struct aoedev *d);
-int aoedev_isbusy(struct aoedev *d);
int aoedev_flush(const char __user *str, size_t size);
int aoenet_init(void);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index d00293ba3b45..41f818be2f7e 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -668,16 +668,16 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
u16 n;
/* word 83: command set supported */
- n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1]));
+ n = get_unaligned_le16(&id[83 << 1]);
/* word 86: command set/feature enabled */
- n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1]));
+ n |= get_unaligned_le16(&id[86 << 1]);
if (n & (1<<10)) { /* bit 10: LBA 48 */
d->flags |= DEVFL_EXT;
/* word 100: number lba48 sectors */
- ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1]));
+ ssize = get_unaligned_le64(&id[100 << 1]);
/* set as in ide-disk.c:init_idedisk_capacity */
d->geo.cylinders = ssize;
@@ -688,12 +688,12 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
d->flags &= ~DEVFL_EXT;
/* number lba28 sectors */
- ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1]));
+ ssize = get_unaligned_le32(&id[60 << 1]);
/* NOTE: obsolete in ATA 6 */
- d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1]));
- d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
- d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
+ d->geo.cylinders = get_unaligned_le16(&id[54 << 1]);
+ d->geo.heads = get_unaligned_le16(&id[55 << 1]);
+ d->geo.sectors = get_unaligned_le16(&id[56 << 1]);
}
if (d->ssize != ssize)
@@ -755,11 +755,13 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector
{
unsigned long n_sect = bio->bi_size >> 9;
const int rw = bio_data_dir(bio);
+ struct hd_struct *part;
- all_stat_inc(disk, ios[rw], sector);
- all_stat_add(disk, ticks[rw], duration, sector);
- all_stat_add(disk, sectors[rw], n_sect, sector);
- all_stat_add(disk, io_ticks, duration, sector);
+ part = get_part(disk, sector);
+ all_stat_inc(disk, part, ios[rw], sector);
+ all_stat_add(disk, part, ticks[rw], duration, sector);
+ all_stat_add(disk, part, sectors[rw], n_sect, sector);
+ all_stat_add(disk, part, io_ticks, duration, sector);
}
void
@@ -779,7 +781,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
u16 aoemajor;
hin = (struct aoe_hdr *) skb_mac_header(skb);
- aoemajor = be16_to_cpu(get_unaligned(&hin->major));
+ aoemajor = get_unaligned_be16(&hin->major);
d = aoedev_by_aoeaddr(aoemajor, hin->minor);
if (d == NULL) {
snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
@@ -791,7 +793,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
spin_lock_irqsave(&d->lock, flags);
- n = be32_to_cpu(get_unaligned(&hin->tag));
+ n = get_unaligned_be32(&hin->tag);
t = gettgt(d, hin->src);
if (t == NULL) {
printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n",
@@ -806,9 +808,9 @@ aoecmd_ata_rsp(struct sk_buff *skb)
snprintf(ebuf, sizeof ebuf,
"%15s e%d.%d tag=%08x@%08lx\n",
"unexpected rsp",
- be16_to_cpu(get_unaligned(&hin->major)),
+ get_unaligned_be16(&hin->major),
hin->minor,
- be32_to_cpu(get_unaligned(&hin->tag)),
+ get_unaligned_be32(&hin->tag),
jiffies);
aoechr_error(ebuf);
return;
@@ -873,7 +875,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
printk(KERN_INFO
"aoe: unrecognized ata command %2.2Xh for %d.%d\n",
ahout->cmdstat,
- be16_to_cpu(get_unaligned(&hin->major)),
+ get_unaligned_be16(&hin->major),
hin->minor);
}
}
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index f9a1cd9edb77..a1d813ab0d6b 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -18,24 +18,6 @@ static void skbpoolfree(struct aoedev *d);
static struct aoedev *devlist;
static DEFINE_SPINLOCK(devlist_lock);
-int
-aoedev_isbusy(struct aoedev *d)
-{
- struct aoetgt **t, **te;
- struct frame *f, *e;
-
- t = d->targets;
- te = t + NTARGETS;
- for (; t < te && *t; t++) {
- f = (*t)->frames;
- e = f + (*t)->nframes;
- for (; f < e; f++)
- if (f->tag != FREETAG)
- return 1;
- }
- return 0;
-}
-
struct aoedev *
aoedev_by_aoeaddr(int maj, int min)
{
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 18d243c73eee..d625169c8e48 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -128,7 +128,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
skb_push(skb, ETH_HLEN); /* (1) */
h = (struct aoe_hdr *) skb_mac_header(skb);
- n = be32_to_cpu(get_unaligned(&h->tag));
+ n = get_unaligned_be32(&h->tag);
if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
goto exit;
@@ -140,7 +140,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
printk(KERN_ERR
"%s%d.%d@%s; ecode=%d '%s'\n",
"aoe: error packet from ",
- be16_to_cpu(get_unaligned(&h->major)),
+ get_unaligned_be16(&h->major),
h->minor, skb->dev->name,
h->err, aoe_errlist[n]);
goto exit;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index e8e38faeafd8..a196ef7f147f 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -387,10 +387,14 @@ static struct block_device_operations brd_fops = {
*/
static int rd_nr;
int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
+static int max_part;
+static int part_shift;
module_param(rd_nr, int, 0);
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
module_param(rd_size, int, 0);
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
+module_param(max_part, int, 0);
+MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
@@ -435,11 +439,11 @@ static struct brd_device *brd_alloc(int i)
blk_queue_max_sectors(brd->brd_queue, 1024);
blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
- disk = brd->brd_disk = alloc_disk(1);
+ disk = brd->brd_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;
disk->major = RAMDISK_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &brd_fops;
disk->private_data = brd;
disk->queue = brd->brd_queue;
@@ -523,7 +527,12 @@ static int __init brd_init(void)
* themselves and have kernel automatically instantiate actual
* device on-demand.
*/
- if (rd_nr > 1UL << MINORBITS)
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
+ if (rd_nr > 1UL << (MINORBITS - part_shift))
return -EINVAL;
if (rd_nr) {
@@ -531,7 +540,7 @@ static int __init brd_init(void)
range = rd_nr;
} else {
nr = CONFIG_BLK_DEV_RAM_COUNT;
- range = 1UL << MINORBITS;
+ range = 1UL << (MINORBITS - part_shift);
}
if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
@@ -570,7 +579,7 @@ static void __exit brd_exit(void)
unsigned long range;
struct brd_device *brd, *next;
- range = rd_nr ? rd_nr : 1UL << MINORBITS;
+ range = rd_nr ? rd_nr : 1UL << (MINORBITS - part_shift);
list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
brd_del_one(brd);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index cf6083a1f928..e336b05fe4a7 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -425,16 +425,12 @@ static void __devinit cciss_procinit(int i)
struct proc_dir_entry *pde;
if (proc_cciss == NULL)
- proc_cciss = proc_mkdir("cciss", proc_root_driver);
+ proc_cciss = proc_mkdir("driver/cciss", NULL);
if (!proc_cciss)
return;
- pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
+ pde = proc_create_data(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
S_IROTH, proc_cciss,
- &cciss_proc_fops);
- if (!pde)
- return;
-
- pde->data = hba[i];
+ &cciss_proc_fops, hba[i]);
}
#endif /* CONFIG_PROC_FS */
@@ -3700,7 +3696,7 @@ static void __exit cciss_cleanup(void)
cciss_remove_one(hba[i]->pdev);
}
}
- remove_proc_entry("cciss", proc_root_driver);
+ remove_proc_entry("driver/cciss", NULL);
}
static void fail_all_cmds(unsigned long ctlr)
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 69199185ff4b..09c14341e6e3 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -214,7 +214,7 @@ static struct proc_dir_entry *proc_array;
static void __init ida_procinit(int i)
{
if (proc_array == NULL) {
- proc_array = proc_mkdir("cpqarray", proc_root_driver);
+ proc_array = proc_mkdir("driver/cpqarray", NULL);
if (!proc_array) return;
}
@@ -1796,7 +1796,7 @@ static void __exit cpqarray_exit(void)
}
}
- remove_proc_entry("cpqarray", proc_root_driver);
+ remove_proc_entry("driver/cpqarray", NULL);
}
module_init(cpqarray_init)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 7652e87d60c5..395f8ea7981c 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4526,14 +4526,15 @@ static void __init parse_floppy_cfg_string(char *cfg)
}
}
-int __init init_module(void)
+static int __init floppy_module_init(void)
{
if (floppy)
parse_floppy_cfg_string(floppy);
return floppy_init();
}
+module_init(floppy_module_init);
-void cleanup_module(void)
+static void __exit floppy_module_exit(void)
{
int drive;
@@ -4562,6 +4563,7 @@ void cleanup_module(void)
/* eject disk, if any */
fd_eject(0);
}
+module_exit(floppy_module_exit);
module_param(floppy, charp, 0);
module_param(FLOPPY_IRQ, int, 0);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f7f163557aa0..d3a25b027ff9 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -546,7 +546,7 @@ static void loop_unplug(struct request_queue *q)
{
struct loop_device *lo = q->queuedata;
- clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+ queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q);
blk_run_address_space(lo->lo_backing_file->f_mapping);
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 60cc54368b66..ad98dda6037d 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -29,6 +29,7 @@
#include <linux/kernel.h>
#include <net/sock.h>
#include <linux/net.h>
+#include <linux/kthread.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -55,6 +56,7 @@ static unsigned int debugflags;
static unsigned int nbds_max = 16;
static struct nbd_device *nbd_dev;
+static int max_part;
/*
* Use just one lock (or at most 1 per NIC). Two arguments for this:
@@ -337,7 +339,7 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
}
req = nbd_find_request(lo, *(struct request **)reply.handle);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
result = PTR_ERR(req);
if (result != -ENOENT)
goto harderror;
@@ -441,6 +443,85 @@ static void nbd_clear_que(struct nbd_device *lo)
}
+static void nbd_handle_req(struct nbd_device *lo, struct request *req)
+{
+ if (!blk_fs_request(req))
+ goto error_out;
+
+ nbd_cmd(req) = NBD_CMD_READ;
+ if (rq_data_dir(req) == WRITE) {
+ nbd_cmd(req) = NBD_CMD_WRITE;
+ if (lo->flags & NBD_READ_ONLY) {
+ printk(KERN_ERR "%s: Write on read-only\n",
+ lo->disk->disk_name);
+ goto error_out;
+ }
+ }
+
+ req->errors = 0;
+
+ mutex_lock(&lo->tx_lock);
+ if (unlikely(!lo->sock)) {
+ mutex_unlock(&lo->tx_lock);
+ printk(KERN_ERR "%s: Attempted send on closed socket\n",
+ lo->disk->disk_name);
+ req->errors++;
+ nbd_end_request(req);
+ return;
+ }
+
+ lo->active_req = req;
+
+ if (nbd_send_req(lo, req) != 0) {
+ printk(KERN_ERR "%s: Request send failed\n",
+ lo->disk->disk_name);
+ req->errors++;
+ nbd_end_request(req);
+ } else {
+ spin_lock(&lo->queue_lock);
+ list_add(&req->queuelist, &lo->queue_head);
+ spin_unlock(&lo->queue_lock);
+ }
+
+ lo->active_req = NULL;
+ mutex_unlock(&lo->tx_lock);
+ wake_up_all(&lo->active_wq);
+
+ return;
+
+error_out:
+ req->errors++;
+ nbd_end_request(req);
+}
+
+static int nbd_thread(void *data)
+{
+ struct nbd_device *lo = data;
+ struct request *req;
+
+ set_user_nice(current, -20);
+ while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) {
+ /* wait for something to do */
+ wait_event_interruptible(lo->waiting_wq,
+ kthread_should_stop() ||
+ !list_empty(&lo->waiting_queue));
+
+ /* extract request */
+ if (list_empty(&lo->waiting_queue))
+ continue;
+
+ spin_lock_irq(&lo->queue_lock);
+ req = list_entry(lo->waiting_queue.next, struct request,
+ queuelist);
+ list_del_init(&req->queuelist);
+ spin_unlock_irq(&lo->queue_lock);
+
+ /* handle request */
+ nbd_handle_req(lo, req);
+ }
+ return 0;
+}
+
/*
* We always wait for result of write, for now. It would be nice to make it optional
* in future
@@ -456,65 +537,23 @@ static void do_nbd_request(struct request_queue * q)
struct nbd_device *lo;
blkdev_dequeue_request(req);
+
+ spin_unlock_irq(q->queue_lock);
+
dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
req->rq_disk->disk_name, req, req->cmd_type);
- if (!blk_fs_request(req))
- goto error_out;
-
lo = req->rq_disk->private_data;
BUG_ON(lo->magic != LO_MAGIC);
- nbd_cmd(req) = NBD_CMD_READ;
- if (rq_data_dir(req) == WRITE) {
- nbd_cmd(req) = NBD_CMD_WRITE;
- if (lo->flags & NBD_READ_ONLY) {
- printk(KERN_ERR "%s: Write on read-only\n",
- lo->disk->disk_name);
- goto error_out;
- }
- }
-
- req->errors = 0;
- spin_unlock_irq(q->queue_lock);
-
- mutex_lock(&lo->tx_lock);
- if (unlikely(!lo->sock)) {
- mutex_unlock(&lo->tx_lock);
- printk(KERN_ERR "%s: Attempted send on closed socket\n",
- lo->disk->disk_name);
- req->errors++;
- nbd_end_request(req);
- spin_lock_irq(q->queue_lock);
- continue;
- }
-
- lo->active_req = req;
+ spin_lock_irq(&lo->queue_lock);
+ list_add_tail(&req->queuelist, &lo->waiting_queue);
+ spin_unlock_irq(&lo->queue_lock);
- if (nbd_send_req(lo, req) != 0) {
- printk(KERN_ERR "%s: Request send failed\n",
- lo->disk->disk_name);
- req->errors++;
- nbd_end_request(req);
- } else {
- spin_lock(&lo->queue_lock);
- list_add(&req->queuelist, &lo->queue_head);
- spin_unlock(&lo->queue_lock);
- }
-
- lo->active_req = NULL;
- mutex_unlock(&lo->tx_lock);
- wake_up_all(&lo->active_wq);
+ wake_up(&lo->waiting_wq);
spin_lock_irq(q->queue_lock);
- continue;
-
-error_out:
- req->errors++;
- spin_unlock(q->queue_lock);
- nbd_end_request(req);
- spin_lock(q->queue_lock);
}
}
@@ -524,6 +563,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;
int error;
struct request sreq ;
+ struct task_struct *thread;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -537,6 +577,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case NBD_DISCONNECT:
printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
+ blk_rq_init(NULL, &sreq);
sreq.cmd_type = REQ_TYPE_SPECIAL;
nbd_cmd(&sreq) = NBD_CMD_DISC;
/*
@@ -571,10 +612,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
error = -EINVAL;
file = fget(arg);
if (file) {
+ struct block_device *bdev = inode->i_bdev;
inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
lo->file = file;
lo->sock = SOCKET_I(inode);
+ if (max_part > 0)
+ bdev->bd_invalidated = 1;
error = 0;
} else {
fput(file);
@@ -606,7 +650,12 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
case NBD_DO_IT:
if (!lo->file)
return -EINVAL;
+ thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
+ if (IS_ERR(thread))
+ return PTR_ERR(thread);
+ wake_up_process(thread);
error = nbd_do_it(lo);
+ kthread_stop(thread);
if (error)
return error;
sock_shutdown(lo, 1);
@@ -619,6 +668,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
lo->bytesize = 0;
inode->i_bdev->bd_inode->i_size = 0;
set_capacity(lo->disk, 0);
+ if (max_part > 0)
+ ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0);
return lo->harderror;
case NBD_CLEAR_QUE:
/*
@@ -652,6 +703,7 @@ static int __init nbd_init(void)
{
int err = -ENOMEM;
int i;
+ int part_shift;
BUILD_BUG_ON(sizeof(struct nbd_request) != 28);
@@ -659,8 +711,17 @@ static int __init nbd_init(void)
if (!nbd_dev)
return -ENOMEM;
+ if (max_part < 0) {
+ printk(KERN_CRIT "nbd: max_part must be >= 0\n");
+ return -EINVAL;
+ }
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
for (i = 0; i < nbds_max; i++) {
- struct gendisk *disk = alloc_disk(1);
+ struct gendisk *disk = alloc_disk(1 << part_shift);
elevator_t *old_e;
if (!disk)
goto out;
@@ -695,17 +756,18 @@ static int __init nbd_init(void)
nbd_dev[i].file = NULL;
nbd_dev[i].magic = LO_MAGIC;
nbd_dev[i].flags = 0;
+ INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
spin_lock_init(&nbd_dev[i].queue_lock);
INIT_LIST_HEAD(&nbd_dev[i].queue_head);
mutex_init(&nbd_dev[i].tx_lock);
init_waitqueue_head(&nbd_dev[i].active_wq);
+ init_waitqueue_head(&nbd_dev[i].waiting_wq);
nbd_dev[i].blksize = 1024;
nbd_dev[i].bytesize = 0;
disk->major = NBD_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &nbd_fops;
disk->private_data = &nbd_dev[i];
- disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "nbd%d", i);
set_capacity(disk, 0);
add_disk(disk);
@@ -743,7 +805,9 @@ MODULE_DESCRIPTION("Network Block Device");
MODULE_LICENSE("GPL");
module_param(nbds_max, int, 0444);
-MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize.");
+MODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)");
+module_param(max_part, int, 0444);
+MODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)");
#ifndef NDEBUG
module_param(debugflags, int, 0644);
MODULE_PARM_DESC(debugflags, "flags for controlling debug output");
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index df819f8a95a6..570f3b70dce7 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -716,10 +716,8 @@ static int pd_special_command(struct pd_unit *disk,
struct request rq;
int err = 0;
- memset(&rq, 0, sizeof(rq));
- rq.errors = 0;
+ blk_rq_init(NULL, &rq);
rq.rq_disk = disk->gd;
- rq.ref_count = 1;
rq.end_io_data = &wait;
rq.end_io = blk_end_sync_rq;
blk_insert_request(disk->gd->queue, &rq, 0, func);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 18feb1c7c33b..3ba1df93e9e3 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -776,8 +776,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
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);
rq->timeout = 60*HZ;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -2744,7 +2742,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
int i;
int ret = 0;
char b[BDEVNAME_SIZE];
- struct proc_dir_entry *proc;
struct block_device *bdev;
if (pd->pkt_dev == dev) {
@@ -2788,11 +2785,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
goto out_mem;
}
- proc = create_proc_entry(pd->name, 0, pkt_proc);
- if (proc) {
- proc->data = pd;
- proc->proc_fops = &pkt_proc_fops;
- }
+ proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd);
DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
return 0;
@@ -3101,7 +3094,7 @@ static int __init pkt_init(void)
goto out_misc;
}
- pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
+ pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL);
return 0;
@@ -3117,7 +3110,7 @@ out2:
static void __exit pkt_exit(void)
{
- remove_proc_entry(DRIVER_NAME, proc_root_driver);
+ remove_proc_entry("driver/"DRIVER_NAME, NULL);
misc_deregister(&pkt_misc);
pkt_debugfs_cleanup();
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index 7483f947f0e9..d797e209951d 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -102,8 +102,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
dev_dbg(&dev->sbd.core,
"%s:%u: bio %u: %u segs %u sectors from %lu\n",
__func__, __LINE__, i, bio_segments(iter.bio),
- bio_sectors(iter.bio),
- (unsigned long)iter.bio->bi_sector);
+ bio_sectors(iter.bio), iter.bio->bi_sector);
size = bvec->bv_len;
buf = bvec_kmap_irq(bvec, &flags);
@@ -406,7 +405,6 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req)
dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
- memset(req->cmd, 0, sizeof(req->cmd));
req->cmd_type = REQ_TYPE_FLUSH;
}
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 27bfe72aab59..3a281ef11ffa 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -205,6 +205,7 @@ struct ub_scsi_cmd {
unsigned char key, asc, ascq; /* May be valid if error==-EIO */
int stat_count; /* Retries getting status. */
+ unsigned int timeo; /* jiffies until rq->timeout changes */
unsigned int len; /* Requested length */
unsigned int current_sg;
@@ -318,6 +319,7 @@ struct ub_dev {
int openc; /* protected by ub_lock! */
/* kref is too implicit for our taste */
int reset; /* Reset is running */
+ int bad_resid;
unsigned int tagcnt;
char name[12];
struct usb_device *dev;
@@ -764,6 +766,12 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
cmd->cdb_len = rq->cmd_len;
cmd->len = rq->data_len;
+
+ /*
+ * To reapply this to every URB is not as incorrect as it looks.
+ * In return, we avoid any complicated tracking calculations.
+ */
+ cmd->timeo = rq->timeout;
}
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -785,10 +793,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
scsi_status = 0;
} else {
if (cmd->act_len != cmd->len) {
- if ((cmd->key == MEDIUM_ERROR ||
- cmd->key == UNIT_ATTENTION) &&
- ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
- return;
scsi_status = SAM_STAT_CHECK_CONDITION;
} else {
scsi_status = 0;
@@ -804,7 +808,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
else
scsi_status = DID_ERROR << 16;
} else {
- if (cmd->error == -EIO) {
+ if (cmd->error == -EIO &&
+ (cmd->key == 0 ||
+ cmd->key == MEDIUM_ERROR ||
+ cmd->key == UNIT_ATTENTION)) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
@@ -1259,14 +1266,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return;
}
- len = le32_to_cpu(bcs->Residue);
- if (len != cmd->len - cmd->act_len) {
- /*
- * It is all right to transfer less, the caller has
- * to check. But it's not all right if the device
- * counts disagree with our counts.
- */
- goto Bad_End;
+ if (!sc->bad_resid) {
+ len = le32_to_cpu(bcs->Residue);
+ if (len != cmd->len - cmd->act_len) {
+ /*
+ * Only start ignoring if this cmd ended well.
+ */
+ if (cmd->len == cmd->act_len) {
+ printk(KERN_NOTICE "%s: "
+ "bad residual %d of %d, ignoring\n",
+ sc->name, len, cmd->len);
+ sc->bad_resid = 1;
+ }
+ }
}
switch (bcs->Status) {
@@ -1297,8 +1309,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
ub_state_done(sc, cmd, -EIO);
} else {
- printk(KERN_WARNING "%s: "
- "wrong command state %d\n",
+ printk(KERN_WARNING "%s: wrong command state %d\n",
sc->name, cmd->state);
ub_state_done(sc, cmd, -EINVAL);
return;
@@ -1336,7 +1347,10 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return;
}
- sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
@@ -1376,7 +1390,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
return -1;
}
- sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
add_timer(&sc->work_timer);
return 0;
}
@@ -1515,8 +1532,7 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
return;
}
if (cmd->state != UB_CMDST_SENSE) {
- printk(KERN_WARNING "%s: "
- "sense done with bad cmd state %d\n",
+ printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
sc->name, cmd->state);
return;
}
@@ -1720,7 +1736,7 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp,
}
/*
- * This is called once a new disk was seen by the block layer or by ub_probe().
+ * This is called by check_disk_change if we reported a media change.
* The main onjective here is to discover the features of the media such as
* the capacity, read-only status, etc. USB storage generally does not
* need to be spun up, but if we needed it, this would be the place.
@@ -2136,8 +2152,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
}
if (ep_in == NULL || ep_out == NULL) {
- printk(KERN_NOTICE "%s: failed endpoint check\n",
- sc->name);
+ printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
return -ENODEV;
}
@@ -2354,7 +2369,7 @@ static void ub_disconnect(struct usb_interface *intf)
spin_unlock_irqrestore(&ub_lock, flags);
/*
- * Fence stall clearnings, operations triggered by unlinkings and so on.
+ * Fence stall clearings, operations triggered by unlinkings and so on.
* We do not attempt to unlink any URBs, because we do not trust the
* unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
*/
@@ -2399,7 +2414,7 @@ static void ub_disconnect(struct usb_interface *intf)
del_gendisk(lun->disk);
/*
* I wish I could do:
- * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+ * queue_flag_set(QUEUE_FLAG_DEAD, q);
* As it is, we rely on our internal poisoning and let
* the upper levels to spin furiously failing all the I/O.
*/
@@ -2417,7 +2432,7 @@ static void ub_disconnect(struct usb_interface *intf)
spin_unlock_irqrestore(sc->lock, flags);
/*
- * There is virtually no chance that other CPU runs times so long
+ * There is virtually no chance that other CPU runs a timeout so long
* after ub_urb_complete should have called del_timer, but only if HCD
* didn't forget to deliver a callback on unlink.
*/
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 0cfbe8c594a5..84e064ffee52 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -35,7 +35,7 @@ struct virtblk_req
struct list_head list;
struct request *req;
struct virtio_blk_outhdr out_hdr;
- struct virtio_blk_inhdr in_hdr;
+ u8 status;
};
static void blk_done(struct virtqueue *vq)
@@ -48,7 +48,7 @@ static void blk_done(struct virtqueue *vq)
spin_lock_irqsave(&vblk->lock, flags);
while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
int uptodate;
- switch (vbr->in_hdr.status) {
+ switch (vbr->status) {
case VIRTIO_BLK_S_OK:
uptodate = 1;
break;
@@ -101,7 +101,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
sg_init_table(vblk->sg, VIRTIO_MAX_SG);
sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
- sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr));
+ sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
if (rq_data_dir(vbr->req) == WRITE) {
vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
@@ -157,10 +157,25 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
/* We provide getgeo only to please some old bootloader/partitioning tools */
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{
- /* some standard values, similar to sd */
- geo->heads = 1 << 6;
- geo->sectors = 1 << 5;
- geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ struct virtio_blk *vblk = bd->bd_disk->private_data;
+ struct virtio_blk_geometry vgeo;
+ int err;
+
+ /* see if the host passed in geometry config */
+ err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
+ offsetof(struct virtio_blk_config, geometry),
+ &vgeo);
+
+ if (!err) {
+ geo->heads = vgeo.heads;
+ geo->sectors = vgeo.sectors;
+ geo->cylinders = vgeo.cylinders;
+ } else {
+ /* some standard values, similar to sd */
+ geo->heads = 1 << 6;
+ geo->sectors = 1 << 5;
+ geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ }
return 0;
}
@@ -242,12 +257,12 @@ static int virtblk_probe(struct virtio_device *vdev)
index++;
/* If barriers are supported, tell block layer that queue is ordered */
- if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
/* Host must always specify the capacity. */
- __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
- &cap);
+ vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
+ &cap, sizeof(cap));
/* If capacity is too big, truncate with warning. */
if ((sector_t)cap != cap) {
@@ -289,7 +304,6 @@ out:
static void virtblk_remove(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;
- int major = vblk->disk->major;
/* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));
@@ -299,7 +313,6 @@ static void virtblk_remove(struct virtio_device *vdev)
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
- unregister_blkdev(major, "virtblk");
mempool_destroy(vblk->pool);
vdev->config->del_vq(vblk->vq);
kfree(vblk);
@@ -310,7 +323,14 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
+static unsigned int features[] = {
+ VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
+ VIRTIO_BLK_F_GEOMETRY,
+};
+
static struct virtio_driver virtio_blk = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index d771da816d95..f2fff5799ddf 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -137,7 +137,7 @@ static void blkif_restart_queue_callback(void *arg)
schedule_work(&info->work);
}
-int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
+static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
{
/* We don't have real geometry info, but let's at least return
values consistent with the size of the device */
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 2d5853cbd4b0..be20a67f1fa8 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -332,7 +332,7 @@ z2_init(void)
int ret;
if (!MACH_IS_AMIGA)
- return -ENXIO;
+ return -ENODEV;
ret = -EBUSY;
if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME))
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 7e31d5f1bc8a..e5cd856a2fea 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -143,7 +143,7 @@ restart:
int len;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- len = tty->driver->write(tty, skb->data, skb->len);
+ len = tty->ops->write(tty, skb->data, skb->len);
hdev->stat.byte_tx += len;
skb_pull(skb, len);
@@ -190,8 +190,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
- if (tty->driver && tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
hu->proto->flush(hu);
@@ -285,9 +284,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
-
- if (tty->driver && tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
return 0;
}
@@ -373,9 +370,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static int hci_uart_register_dev(struct hci_uart *hu)
diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h
index 414080a4e8ff..1790cc8e431e 100644
--- a/drivers/bluetooth/hci_usb.h
+++ b/drivers/bluetooth/hci_usb.h
@@ -70,7 +70,8 @@ static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
- list_add(&_urb->list, &q->head); _urb->queue = q;
+ /* _urb_unlink needs to know which spinlock to use, thus mb(). */
+ _urb->queue = q; mb(); list_add(&_urb->list, &q->head);
spin_unlock_irqrestore(&q->lock, flags);
}
@@ -78,19 +79,23 @@ static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
- list_add_tail(&_urb->list, &q->head); _urb->queue = q;
+ /* _urb_unlink needs to know which spinlock to use, thus mb(). */
+ _urb->queue = q; mb(); list_add_tail(&_urb->list, &q->head);
spin_unlock_irqrestore(&q->lock, flags);
}
static inline void _urb_unlink(struct _urb *_urb)
{
- struct _urb_queue *q = _urb->queue;
+ struct _urb_queue *q;
unsigned long flags;
- if (q) {
- spin_lock_irqsave(&q->lock, flags);
- list_del(&_urb->list); _urb->queue = NULL;
- spin_unlock_irqrestore(&q->lock, flags);
- }
+
+ mb();
+ q = _urb->queue;
+ /* If q is NULL, it will die at easy-to-debug NULL pointer dereference.
+ No need to BUG(). */
+ spin_lock_irqsave(&q->lock, flags);
+ list_del(&_urb->list); _urb->queue = NULL;
+ spin_unlock_irqrestore(&q->lock, flags);
}
struct hci_usb {
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index ac3829030ac5..69f26eb6415b 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2194,7 +2194,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
if (ret)
break;
- memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = GPCMD_READ_CD;
rq->cmd[1] = 1 << 2;
rq->cmd[2] = (lba >> 24) & 0xff;
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index b74b6c2768a8..5245a4a0ba74 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -144,6 +144,7 @@ static int proc_viocd_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_viocd_operations = {
+ .owner = THIS_MODULE,
.open = proc_viocd_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -679,7 +680,6 @@ static struct vio_driver viocd_driver = {
static int __init viocd_init(void)
{
- struct proc_dir_entry *e;
int ret = 0;
if (!firmware_has_feature(FW_FEATURE_ISERIES))
@@ -719,12 +719,8 @@ static int __init viocd_init(void)
if (ret)
goto out_free_info;
- e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL);
- if (e) {
- e->owner = THIS_MODULE;
- e->proc_fops = &proc_viocd_operations;
- }
-
+ proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL,
+ &proc_viocd_operations);
return 0;
out_free_info:
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 929d4fa73fd9..595a925c62a9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -80,6 +80,15 @@ config VT_HW_CONSOLE_BINDING
information. For framebuffer console users, please refer to
<file:Documentation/fb/fbcon.txt>.
+config DEVKMEM
+ bool "/dev/kmem virtual device support"
+ default y
+ help
+ Say Y here if you want to support the /dev/kmem device. The
+ /dev/kmem device is rarely used, but can be used for certain
+ kind of kernel debugging operations.
+ When in doubt, say "N".
+
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
depends on HAS_IOMEM
@@ -187,6 +196,7 @@ config ESPSERIAL
config MOXA_INTELLIO
tristate "Moxa Intellio support"
depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+ select FW_LOADER
help
Say Y here if you have a Moxa Intellio multiport serial card.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index c69f79598e47..99e6a406efb4 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -35,7 +35,7 @@
//#define AGP_DEBUG 1
#ifdef AGP_DEBUG
-#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __FUNCTION__ , ## y)
+#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __func__ , ## y)
#else
#define DBG(x,y...) do { } while (0)
#endif
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 3d468f502d2d..37457e5a4f2b 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -832,33 +832,34 @@ static void change_speed(struct async_struct *info,
local_irq_restore(flags);
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct async_struct *info;
unsigned long flags;
if (!tty)
- return;
+ return 0;
info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!info->xmit.buf)
- return;
+ return 0;
local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE) == 0) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit.buf[info->xmit.head++] = ch;
info->xmit.head &= SERIAL_XMIT_SIZE-1;
local_irq_restore(flags);
+ return 1;
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -1074,6 +1075,7 @@ static int get_serial_info(struct async_struct * info,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.type = state->type;
tmp.line = state->line;
tmp.port = state->port;
@@ -1084,6 +1086,7 @@ static int get_serial_info(struct async_struct * info,
tmp.close_delay = state->close_delay;
tmp.closing_wait = state->closing_wait;
tmp.custom_divisor = state->custom_divisor;
+ unlock_kernel();
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -1099,13 +1102,17 @@ static int set_serial_info(struct async_struct * info,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
+
+ lock_kernel();
state = info->state;
old_state = *state;
change_irq = new_serial.irq != state->irq;
change_port = (new_serial.port != state->port);
- if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size))
+ if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
+ unlock_kernel();
return -EINVAL;
+ }
if (!serial_isroot()) {
if ((new_serial.baud_base != state->baud_base) ||
@@ -1122,8 +1129,10 @@ static int set_serial_info(struct async_struct * info,
goto check_and_exit;
}
- if (new_serial.baud_base < 9600)
+ if (new_serial.baud_base < 9600) {
+ unlock_kernel();
return -EINVAL;
+ }
/*
* OK, past this point, all the error checking has been done.
@@ -1157,6 +1166,7 @@ check_and_exit:
}
} else
retval = startup(info);
+ unlock_kernel();
return retval;
}
@@ -1496,8 +1506,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
rs_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1530,6 +1539,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
return; /* Just in case.... */
orig_jiffies = jiffies;
+
+ lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -1570,6 +1581,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
__set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 17d54315e146..cdd876dbb2b0 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -14,6 +14,7 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/miscdevice.h>
#include <linux/apm_bios.h>
#include <linux/capability.h>
@@ -493,11 +494,10 @@ static struct miscdevice apm_device = {
* -1: Unknown
* 8) min = minutes; sec = seconds
*/
-static int apm_get_info(char *buf, char **start, off_t fpos, int length)
+static int proc_apm_show(struct seq_file *m, void *v)
{
struct apm_power_info info;
char *units;
- int ret;
info.ac_line_status = 0xff;
info.battery_status = 0xff;
@@ -515,14 +515,27 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
case 1: units = "sec"; break;
}
- ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+ seq_printf(m, "%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;
+ return 0;
}
+
+static int proc_apm_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_apm_show, NULL);
+}
+
+static const struct file_operations apm_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_apm_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
static int kapmd(void *arg)
@@ -593,7 +606,7 @@ static int __init apm_init(void)
wake_up_process(kapmd_tsk);
#ifdef CONFIG_PROC_FS
- create_proc_info_entry("apm", 0, NULL, apm_get_info);
+ proc_create("apm", 0, NULL, &apm_proc_fops);
#endif
ret = misc_register(&apm_device);
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index a7c4990b5b6b..31d08b641f5b 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -199,7 +199,7 @@ static int __init applicom_init(void)
if (pci_enable_device(dev))
return -EIO;
- RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO);
+ RamIO = ioremap_nocache(pci_resource_start(dev, 0), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
@@ -254,7 +254,7 @@ static int __init applicom_init(void)
/* Now try the specified ISA cards */
for (i = 0; i < MAX_ISA_BOARD; i++) {
- RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
+ RamIO = ioremap_nocache(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1);
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 6b104e45a322..4246b8e36cb3 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -277,6 +277,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);
static void update_user_maps(void)
{
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e4f579c3e245..ef73e72daedc 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -21,7 +21,6 @@
*
* This version supports shared IRQ's (only for PCI boards).
*
- * $Log: cyclades.c,v $
* Prevent users from opening non-existing Z ports.
*
* Revision 2.3.2.8 2000/07/06 18:14:16 ivan
@@ -62,7 +61,7 @@
* Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
*
* Revision 2.3.2.2 1999/10/01 11:27:43 ivan
- * Fixed bug in cyz_poll that would make all ports but port 0
+ * Fixed bug in cyz_poll that would make all ports but port 0
* unable to transmit/receive data (Cyclades-Z only);
* Implemented logic to prevent the RX buffer from being stuck with data
* due to a driver / firmware race condition in interrupt op mode
@@ -83,25 +82,25 @@
* Revision 2.3.1.1 1999/07/15 16:45:53 ivan
* Removed CY_PROC conditional compilation;
* Implemented SMP-awareness for the driver;
- * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
+ * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
* functions;
* The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
* (irq=NN) as parameters (only for ISA boards);
- * Fixed bug in set_line_char that would prevent the Cyclades-Z
+ * Fixed bug in set_line_char that would prevent the Cyclades-Z
* ports from being configured at speeds above 115.2Kbps;
* Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
* switching from working properly;
- * The driver now only prints IRQ info for the Cyclades-Z if it's
+ * The driver now only prints IRQ info for the Cyclades-Z if it's
* configured to work in interrupt mode;
*
* Revision 2.2.2.3 1999/06/28 11:13:29 ivan
* Added support for interrupt mode operation for the Z cards;
* Removed the driver inactivity control for the Z;
- * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
+ * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
* the Z firmware is not loaded yet;
- * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
+ * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
* same functionality;
- * Implemented workaround for IRQ setting loss on the PCI configuration
+ * Implemented workaround for IRQ setting loss on the PCI configuration
* registers after a PCI bridge EEPROM reload (affects PLX9060 only);
*
* Revision 2.2.2.2 1999/05/14 17:18:15 ivan
@@ -112,22 +111,22 @@
* BREAK implementation changed in order to make use of the 'break_ctl'
* TTY facility;
* Fixed typo in TTY structure field 'driver_name';
- * Included a PCI bridge reset and EEPROM reload in the board
+ * Included a PCI bridge reset and EEPROM reload in the board
* initialization code (for both Y and Z series).
*
* Revision 2.2.2.1 1999/04/08 16:17:43 ivan
- * Fixed a bug in cy_wait_until_sent that was preventing the port to be
+ * Fixed a bug in cy_wait_until_sent that was preventing the port to be
* closed properly after a SIGINT;
* Module usage counter scheme revisited;
* Added support to the upcoming Y PCI boards (i.e., support to additional
* PCI Device ID's).
- *
+ *
* Revision 2.2.1.10 1999/01/20 16:14:29 ivan
* Removed all unnecessary page-alignement operations in ioremap calls
* (ioremap is currently safe for these operations).
*
* Revision 2.2.1.9 1998/12/30 18:18:30 ivan
- * Changed access to PLX PCI bridge registers from I/O to MMIO, in
+ * Changed access to PLX PCI bridge registers from I/O to MMIO, in
* order to make PLX9050-based boards work with certain motherboards.
*
* Revision 2.2.1.8 1998/11/13 12:46:20 ivan
@@ -148,7 +147,7 @@
* Fixed Cyclom-4Yo hardware detection bug.
*
* Revision 2.2.1.4 1998/08/04 11:02:50 ivan
- * /proc/cyclades implementation with great collaboration of
+ * /proc/cyclades implementation with great collaboration of
* Marc Lewis <marc@blarg.net>;
* cyy_interrupt was changed to avoid occurrence of kernel oopses
* during PPP operation.
@@ -157,7 +156,7 @@
* General code review in order to comply with 2.1 kernel standards;
* data loss prevention for slow devices revisited (cy_wait_until_sent
* was created);
- * removed conditional compilation for new/old PCI structure support
+ * removed conditional compilation for new/old PCI structure support
* (now the driver only supports the new PCI structure).
*
* Revision 2.2.1.1 1998/03/19 16:43:12 ivan
@@ -168,7 +167,7 @@
* cleaned up the data loss fix;
* fixed XON/XOFF handling once more (Cyclades-Z);
* general review of the driver routines;
- * introduction of a mechanism to prevent data loss with slow
+ * introduction of a mechanism to prevent data loss with slow
* printers, by forcing a delay before closing the port.
*
* Revision 2.1.1.2 1998/02/17 16:50:00 ivan
@@ -182,12 +181,12 @@
* Code review for the module cleanup routine;
* fixed RTS and DTR status report for new CD1400's in get_modem_info;
* includes anonymous changes regarding signal_pending.
- *
+ *
* Revision 2.1 1997/11/01 17:42:41 ivan
* Changes in the driver to support Alpha systems (except 8Zo V_1);
* BREAK fix for the Cyclades-Z boards;
* driver inactivity control by FW implemented;
- * introduction of flag that allows driver to take advantage of
+ * introduction of flag that allows driver to take advantage of
* a special CD1400 feature related to HW flow control;
* added support for the CD1400 rev. J (Cyclom-Y boards);
* introduction of ioctls to:
@@ -196,17 +195,17 @@
* - adjust the polling interval (Cyclades-Z);
*
* Revision 1.36.4.33 1997/06/27 19:00:00 ivan
- * Fixes related to kernel version conditional
+ * Fixes related to kernel version conditional
* compilation.
- *
+ *
* Revision 1.36.4.32 1997/06/14 19:30:00 ivan
- * Compatibility issues between kernels 2.0.x and
+ * Compatibility issues between kernels 2.0.x and
* 2.1.x (mainly related to clear_bit function).
- *
+ *
* Revision 1.36.4.31 1997/06/03 15:30:00 ivan
- * Changes to define the memory window according to the
+ * Changes to define the memory window according to the
* board type.
- *
+ *
* Revision 1.36.4.30 1997/05/16 15:30:00 daniel
* Changes to support new cycladesZ boards.
*
@@ -624,7 +623,7 @@
#undef CY_PCI_DEBUG
/*
- * Include section
+ * Include section
*/
#include <linux/module.h>
#include <linux/errno.h>
@@ -649,9 +648,9 @@
#include <linux/firmware.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -668,10 +667,10 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
((readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
-#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
+#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
Z_FPGA_CHECK(card)) && \
- (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
+ (ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
((card).base_addr+ID_ADDRESS))->signature)))
#ifndef SERIAL_XMIT_SIZE
@@ -809,12 +808,12 @@ static char baud_cor3[] = { /* receive threshold */
/*
* The Cyclades driver implements HW flow control as any serial driver.
- * The cyclades_port structure member rflow and the vector rflow_thr
- * allows us to take advantage of a special feature in the CD1400 to avoid
- * data loss even when the system interrupt latency is too high. These flags
- * are to be used only with very special applications. Setting these flags
- * requires the use of a special cable (DTR and RTS reversed). In the new
- * CD1400-based boards (rev. 6.00 or later), there is no need for special
+ * The cyclades_port structure member rflow and the vector rflow_thr
+ * allows us to take advantage of a special feature in the CD1400 to avoid
+ * data loss even when the system interrupt latency is too high. These flags
+ * are to be used only with very special applications. Setting these flags
+ * requires the use of a special cable (DTR and RTS reversed). In the new
+ * CD1400-based boards (rev. 6.00 or later), there is no need for special
* cables.
*/
@@ -841,14 +840,22 @@ static int cy_chip_offset[] = { 0x0000,
#ifdef CONFIG_PCI
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 */
+ /* PCI < 1Mb */
+ { 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) },
+ /* 4Y 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) },
+ /* 8Y 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) },
+ /* Z 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) },
{ } /* end of table */
};
MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
@@ -905,15 +912,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
This function is only called from inside spinlock-protected code.
*/
-static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
+static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
{
unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (readb(base_addr + (CyCCR << index)) == 0) {
+ if (readb(base_addr + (CyCCR << index)) == 0)
break;
- }
udelay(10L);
}
/* if the CCR never cleared, the previous command
@@ -929,7 +935,7 @@ static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
-static unsigned detect_isa_irq(void __iomem * address)
+static unsigned detect_isa_irq(void __iomem *address)
{
int irq;
unsigned long irqs, flags;
@@ -1038,7 +1044,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (data & CyFRAME) {
- tty_insert_flip_char( tty,
+ tty_insert_flip_char(tty,
readb(base_addr + (CyRDSR <<
index)), TTY_FRAME);
info->icount.rx++;
@@ -1320,7 +1326,8 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
+ printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
+ irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1375,12 +1382,12 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
-/******** Start of block of Cyclades-Z specific code *********/
+/******** Start of block of Cyclades-Z specific code *******/
/***********************************************************/
static int
cyz_fetch_msg(struct cyclades_card *cinfo,
- __u32 * channel, __u8 * cmd, __u32 * param)
+ __u32 *channel, __u8 *cmd, __u32 *param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -1388,9 +1395,8 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
unsigned long loc_doorbell;
firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo))
return -1;
- }
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@@ -1418,9 +1424,9 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
unsigned int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo))
return -1;
- }
+
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@@ -1428,9 +1434,8 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
pci_doorbell =
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
while ((readl(pci_doorbell) & 0xff) != 0) {
- if (index++ == 1000) {
+ if (index++ == 1000)
return (int)(readl(pci_doorbell) & 0xff);
- }
udelay(50L);
}
cy_writel(&board_ctrl->hcmd_channel, channel);
@@ -1504,7 +1509,8 @@ static void cyz_handle_rx(struct cyclades_port *info,
while (len--) {
data = readb(cinfo->base_addr + rx_bufaddr +
new_rx_get);
- new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
+ new_rx_get = (new_rx_get + 1) &
+ (rx_bufsize - 1);
tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
@@ -1636,7 +1642,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
special_count = 0;
delta_count = 0;
info = &cinfo->ports[channel];
- if ((tty = info->tty) == NULL)
+ tty = info->tty;
+ if (tty == NULL)
continue;
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
@@ -1732,7 +1739,8 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
+ printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
+ irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1851,9 +1859,8 @@ static int startup(struct cyclades_port *info)
}
if (!info->type) {
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
free_page(page);
goto errout;
}
@@ -1904,9 +1911,8 @@ static int startup(struct cyclades_port *info)
readb(base_addr + (CySRER << index)) | CyRxData);
info->flags |= ASYNC_INITIALIZED;
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
info->breakon = info->breakoff = 0;
memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -1925,9 +1931,8 @@ static int startup(struct cyclades_port *info)
base_addr = card->base_addr;
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return -ENODEV;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -1990,9 +1995,8 @@ static int startup(struct cyclades_port *info)
/* enable send, recv, modem !!! */
info->flags |= ASYNC_INITIALIZED;
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
info->breakon = info->breakoff = 0;
memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -2061,9 +2065,8 @@ static void shutdown(struct cyclades_port *info)
void __iomem *base_addr;
int chip, channel, index;
- if (!(info->flags & ASYNC_INITIALIZED)) {
+ if (!(info->flags & ASYNC_INITIALIZED))
return;
- }
card = info->card;
channel = info->line - card->first_line;
@@ -2105,9 +2108,8 @@ static void shutdown(struct cyclades_port *info)
/* it may be appropriate to clear _XMIT at
some later date (after testing)!!! */
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
@@ -2124,9 +2126,8 @@ static void shutdown(struct cyclades_port *info)
#endif
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -2157,9 +2158,8 @@ static void shutdown(struct cyclades_port *info)
#endif
}
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2204,7 +2204,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
* If non-blocking mode is set, then make the check up front
* and then exit.
*/
- if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -2301,7 +2302,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
return -EINVAL;
}
- zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
+ zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)
+ & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
@@ -2378,9 +2380,9 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
int retval;
line = tty->index;
- if ((tty->index < 0) || (NR_PORTS <= line)) {
+ if (tty->index < 0 || NR_PORTS <= line)
return -ENODEV;
- }
+
for (i = 0; i < NR_CARDS; i++)
if (line < cy_card[i].first_line + cy_card[i].nports &&
line >= cy_card[i].first_line)
@@ -2388,9 +2390,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
if (i >= NR_CARDS)
return -ENODEV;
info = &cy_card[i].ports[line - cy_card[i].first_line];
- if (info->line < 0) {
+ if (info->line < 0)
return -ENODEV;
- }
/* If the card's firmware hasn't been loaded,
treat it as absent from the system. This
@@ -2456,9 +2457,9 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
#endif
tty->driver_data = info;
info->tty = tty;
- if (serial_paranoia_check(info, tty->name, "cy_open")) {
+ if (serial_paranoia_check(info, tty->name, "cy_open"))
return -ENODEV;
- }
+
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
info->count);
@@ -2482,9 +2483,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* Start up serial port
*/
retval = startup(info);
- if (retval) {
+ if (retval)
return retval;
- }
retval = block_til_ready(tty, filp, info);
if (retval) {
@@ -2522,6 +2522,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
return; /* Just in case.... */
orig_jiffies = jiffies;
+ lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -2573,11 +2574,47 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
+ unlock_kernel();
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
#endif
}
+static void cy_flush_buffer(struct tty_struct *tty)
+{
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel, retval;
+ unsigned long flags;
+
+#ifdef CY_DEBUG_IO
+ printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
+#endif
+
+ if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
+ return;
+
+ card = info->card;
+ channel = info->line - card->first_line;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ spin_unlock_irqrestore(&card->card_lock, flags);
+
+ if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
+ buffers as well */
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
+ if (retval != 0) {
+ printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ }
+ tty_wakeup(tty);
+} /* cy_flush_buffer */
+
+
/*
* This routine is called when a particular tty device is closed.
*/
@@ -2591,9 +2628,8 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
#endif
- if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
return;
- }
card = info->card;
@@ -2641,9 +2677,9 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
*/
tty->closing = 1;
spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->closing_wait);
- }
+
spin_lock_irqsave(&card->card_lock, flags);
if (!IS_CYC_Z(*card)) {
@@ -2657,15 +2693,16 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) & ~CyRxData);
if (info->flags & ASYNC_INITIALIZED) {
- /* Waiting for on-board buffers to be empty before closing
- the port */
+ /* Waiting for on-board buffers to be empty before
+ closing the port */
spin_unlock_irqrestore(&card->card_lock, flags);
cy_wait_until_sent(tty, info->timeout);
spin_lock_irqsave(&card->card_lock, flags);
}
} else {
#ifdef Z_WAKE
- /* Waiting for on-board buffers to be empty before closing the port */
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
void __iomem *base_addr = card->base_addr;
struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl =
@@ -2689,8 +2726,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
spin_unlock_irqrestore(&card->card_lock, flags);
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ cy_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
@@ -2738,17 +2774,16 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write")) {
+ if (serial_paranoia_check(info, tty->name, "cy_write"))
return 0;
- }
if (!info->xmit_buf)
return 0;
spin_lock_irqsave(&info->card->card_lock, flags);
while (1) {
- c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
- (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
+ c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
+ c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
@@ -2766,9 +2801,9 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
start_xmit(info);
- }
+
return ret;
} /* cy_write */
@@ -2779,7 +2814,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
* done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored.
*/
-static void cy_put_char(struct tty_struct *tty, unsigned char ch)
+static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
@@ -2789,15 +2824,15 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->card->card_lock, flags);
if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
spin_unlock_irqrestore(&info->card->card_lock, flags);
- return;
+ return 0;
}
info->xmit_buf[info->xmit_head++] = ch;
@@ -2806,11 +2841,12 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
spin_unlock_irqrestore(&info->card->card_lock, flags);
+ return 1;
} /* cy_put_char */
/*
* This routine is called by the kernel after it has written a
- * series of characters to the tty device using put_char().
+ * series of characters to the tty device using put_char().
*/
static void cy_flush_chars(struct tty_struct *tty)
{
@@ -2882,6 +2918,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
int char_count;
__u32 tx_put, tx_get, tx_bufsize;
+ lock_kernel();
firm_id = card->base_addr + ID_ADDRESS;
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -2899,6 +2936,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt + char_count);
#endif
+ unlock_kernel();
return info->xmit_cnt + char_count;
}
#endif /* Z_EXT_CHARS_IN_BUFFER */
@@ -2950,12 +2988,12 @@ static void set_line_char(struct cyclades_port *info)
int baud, baud_rate = 0;
int i;
- if (!info->tty || !info->tty->termios) {
+ if (!info->tty || !info->tty->termios)
return;
- }
- if (info->line == -1) {
+
+ if (info->line == -1)
return;
- }
+
cflag = info->tty->termios->c_cflag;
iflag = info->tty->termios->c_iflag;
@@ -2994,13 +3032,11 @@ static void set_line_char(struct cyclades_port *info)
}
/* find the baud index */
for (i = 0; i < 20; i++) {
- if (baud == baud_table[i]) {
+ if (baud == baud_table[i])
break;
- }
}
- if (i == 20) {
+ if (i == 20)
i = 19; /* CD1400_MAX_SPEED */
- }
if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
@@ -3059,18 +3095,16 @@ static void set_line_char(struct cyclades_port *info)
info->cor1 = Cy_8_BITS;
break;
}
- if (cflag & CSTOPB) {
+ if (cflag & CSTOPB)
info->cor1 |= Cy_2_STOP;
- }
+
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & PARODD)
info->cor1 |= CyPARITY_O;
- } else {
+ else
info->cor1 |= CyPARITY_E;
- }
- } else {
+ } else
info->cor1 |= CyPARITY_NONE;
- }
/* CTS flow control flag */
if (cflag & CRTSCTS) {
@@ -3123,7 +3157,8 @@ static void set_line_char(struct cyclades_port *info)
cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
CyCOR3ch, index);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
+ /* !!! Is this needed? */
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
cy_writeb(base_addr + (CyRTPR << index),
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
@@ -3191,9 +3226,8 @@ static void set_line_char(struct cyclades_port *info)
#endif
}
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
@@ -3206,9 +3240,8 @@ static void set_line_char(struct cyclades_port *info)
int retval;
firm_id = card->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -3268,14 +3301,12 @@ static void set_line_char(struct cyclades_port *info)
readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
}
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & PARODD)
cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
- } else {
+ else
cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
- }
- } else {
+ } else
cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
- }
/* CTS flow control flag */
if (cflag & CRTSCTS) {
@@ -3305,11 +3336,10 @@ static void set_line_char(struct cyclades_port *info)
}
/* CD sensitivity */
- if (cflag & CLOCAL) {
+ if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
- } else {
+ else
info->flags |= ASYNC_CHECK_CD;
- }
if (baud == 0) { /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
@@ -3325,21 +3355,20 @@ static void set_line_char(struct cyclades_port *info)
#endif
}
- retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
"was %x\n", info->line, retval);
}
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
}
} /* set_line_char */
static int
get_serial_info(struct cyclades_port *info,
- struct serial_struct __user * retinfo)
+ struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
struct cyclades_card *cinfo = info->card;
@@ -3363,7 +3392,7 @@ get_serial_info(struct cyclades_port *info,
static int
set_serial_info(struct cyclades_port *info,
- struct serial_struct __user * new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
struct cyclades_port old_info;
@@ -3417,7 +3446,7 @@ check_and_exit:
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
+static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
{
struct cyclades_card *card;
int chip, channel, index;
@@ -3461,9 +3490,11 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
+ lock_kernel();
+
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
@@ -3506,10 +3537,12 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
} else {
result = 0;
+ unlock_kernel();
return -ENODEV;
}
}
+ unlock_kernel();
return result;
} /* cy_tiomget */
@@ -3528,7 +3561,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
card = info->card;
@@ -3727,8 +3760,8 @@ static void cy_break(struct tty_struct *tty, int break_state)
spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_break */
-static int
-get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
+static int get_mon_info(struct cyclades_port *info,
+ struct cyclades_monitor __user *mon)
{
if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
@@ -3767,8 +3800,8 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
return 0;
} /* set_threshold */
-static int
-get_threshold(struct cyclades_port *info, unsigned long __user * value)
+static int get_threshold(struct cyclades_port *info,
+ unsigned long __user *value)
{
struct cyclades_card *card;
void __iomem *base_addr;
@@ -3789,15 +3822,15 @@ get_threshold(struct cyclades_port *info, unsigned long __user * value)
return 0;
} /* get_threshold */
-static int
-set_default_threshold(struct cyclades_port *info, unsigned long value)
+static int set_default_threshold(struct cyclades_port *info,
+ unsigned long value)
{
info->default_threshold = value & 0x0f;
return 0;
} /* set_default_threshold */
-static int
-get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
+static int get_default_threshold(struct cyclades_port *info,
+ unsigned long __user *value)
{
return put_user(info->default_threshold, value);
} /* get_default_threshold */
@@ -3824,7 +3857,8 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
return 0;
} /* set_timeout */
-static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
+static int get_timeout(struct cyclades_port *info,
+ unsigned long __user *value)
{
struct cyclades_card *card;
void __iomem *base_addr;
@@ -3851,8 +3885,8 @@ static int set_default_timeout(struct cyclades_port *info, unsigned long value)
return 0;
} /* set_default_timeout */
-static int
-get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
+static int get_default_timeout(struct cyclades_port *info,
+ unsigned long __user *value)
{
return put_user(info->default_timeout, value);
} /* get_default_timeout */
@@ -3880,6 +3914,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
info->line, cmd, arg);
#endif
+ lock_kernel();
switch (cmd) {
case CYGETMON:
@@ -3936,7 +3971,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
break;
#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
- info->closing_wait = (unsigned short)arg *HZ / 100;
+ info->closing_wait = (unsigned short)arg * HZ / 100;
ret_val = 0;
break;
case CYGETWAIT:
@@ -3988,47 +4023,47 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
p_cuser = argp;
ret_val = put_user(cnow.cts, &p_cuser->cts);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.dsr, &p_cuser->dsr);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.rng, &p_cuser->rng);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.dcd, &p_cuser->dcd);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.rx, &p_cuser->rx);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.tx, &p_cuser->tx);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.frame, &p_cuser->frame);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.overrun, &p_cuser->overrun);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.parity, &p_cuser->parity);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.brk, &p_cuser->brk);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
if (ret_val)
- return ret_val;
+ break;
ret_val = 0;
break;
default:
ret_val = -ENOIOCTLCMD;
}
+ unlock_kernel();
#ifdef CY_DEBUG_OTHER
printk(KERN_DEBUG "cyc:cy_ioctl done\n");
#endif
-
return ret_val;
} /* cy_ioctl */
@@ -4113,9 +4148,8 @@ static void cy_throttle(struct tty_struct *tty)
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
+ if (serial_paranoia_check(info, tty->name, "cy_throttle"))
return;
- }
card = info->card;
@@ -4169,12 +4203,11 @@ static void cy_unthrottle(struct tty_struct *tty)
char buf[64];
printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
- tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
+ tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
+ if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
return;
- }
if (I_IXOFF(tty)) {
if (info->x_char)
@@ -4269,47 +4302,14 @@ static void cy_start(struct tty_struct *tty)
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) (channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) | CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
-static void cy_flush_buffer(struct tty_struct *tty)
-{
- struct cyclades_port *info = tty->driver_data;
- struct cyclades_card *card;
- int channel, retval;
- unsigned long flags;
-
-#ifdef CY_DEBUG_IO
- printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
-#endif
-
- if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
- return;
-
- card = info->card;
- channel = info->line - card->first_line;
-
- spin_lock_irqsave(&card->card_lock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irqrestore(&card->card_lock, flags);
-
- if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
- buffers as well */
- spin_lock_irqsave(&card->card_lock, flags);
- retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
- "was %x\n", info->line, retval);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- tty_wakeup(tty);
-} /* cy_flush_buffer */
-
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
@@ -4406,10 +4406,11 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
info->cor3 = 0x08; /* _very_ small rcv threshold */
chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev = readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] <<
- index) + (CyGFRCR << index))) >=
- CD1400_REV_J) {
+ info->chip_rev = readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] << index) +
+ (CyGFRCR << index));
+
+ if (info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[13]; /* Tx BPR */
info->tco = baud_co_60[13]; /* Tx CO */
@@ -4454,7 +4455,8 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
/* Cy_ClrIntr is 0x1800 */
udelay(500L);
- for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
+ for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
+ chip_number++) {
base_addr =
true_base_addr + (cy_chip_offset[chip_number] << index);
mdelay(1);
@@ -4555,12 +4557,11 @@ static int __init cy_detect_isa(void)
/* scan the address table probing for Cyclom-Y/ISA boards */
for (i = 0; i < NR_ISA_ADDRS; i++) {
unsigned int isa_address = cy_isa_addresses[i];
- if (isa_address == 0x0000) {
+ if (isa_address == 0x0000)
return nboard;
- }
/* probe for CD1400... */
- cy_isa_address = ioremap(isa_address, CyISA_Ywin);
+ cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
if (cy_isa_address == NULL) {
printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
"address\n");
@@ -4847,12 +4848,10 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
if (mailbox != 0) {
/* set window to last 512K of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
- //sleep(1);
for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
cy_writeb(tmp, 255);
/* set window to beginning of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
- //sleep(1);
}
retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
@@ -5382,7 +5381,8 @@ static void __exit cy_cleanup_module(void)
del_timer_sync(&cyz_timerlist);
#endif /* CONFIG_CYZ_INTR */
- if ((e1 = tty_unregister_driver(cy_serial_driver)))
+ e1 = tty_unregister_driver(cy_serial_driver);
+ if (e1)
printk(KERN_ERR "failed to unregister Cyclades serial "
"driver(%d)\n", e1);
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index ecee3547a13f..213b3ca3468e 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -160,7 +160,7 @@ struct drm_device;
* \param arg arguments
*/
#define DRM_ERROR(fmt, arg...) \
- printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg)
+ printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg)
/**
* Memory error output.
@@ -170,7 +170,7 @@ struct drm_device;
* \param arg arguments
*/
#define DRM_MEM_ERROR(area, fmt, arg...) \
- printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \
+ printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \
drm_mem_stats[area].name , ##arg)
#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
@@ -187,7 +187,7 @@ struct drm_device;
if ( drm_debug ) \
printk(KERN_DEBUG \
"[" DRM_NAME ":%s] " fmt , \
- __FUNCTION__ , ##arg); \
+ __func__ , ##arg); \
} while (0)
#else
#define DRM_DEBUG(fmt, arg...) do { } while (0)
@@ -238,7 +238,7 @@ do { \
if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \
dev->lock.file_priv != file_priv ) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
- __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
+ __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
dev->lock.file_priv, file_priv ); \
return -EINVAL; \
} \
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 7a1d9a782ddb..9a32169e88fb 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -34,7 +34,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev;
- printk(KERN_ERR "%s\n", __FUNCTION__);
+ printk(KERN_ERR "%s\n", __func__);
if (drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev, state);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 60c9376be486..a86ab30b4620 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -692,7 +692,7 @@ static void i830EmitState(struct drm_device * dev)
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
- DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
+ DRM_DEBUG("%s %x\n", __func__, dirty);
if (dirty & I830_UPLOAD_BUFFERS) {
i830EmitDestVerified(dev, sarea_priv->BufferState);
@@ -1043,7 +1043,7 @@ static void i830_dma_dispatch_flip(struct drm_device * dev)
RING_LOCALS;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
+ __func__,
dev_priv->current_page,
dev_priv->sarea_priv->pf_current_page);
@@ -1206,7 +1206,7 @@ static void i830_dma_quiescent(struct drm_device * dev)
OUT_RING(0);
ADVANCE_LP_RING();
- i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
static int i830_flush_queue(struct drm_device * dev)
@@ -1223,7 +1223,7 @@ static int i830_flush_queue(struct drm_device * dev)
OUT_RING(0);
ADVANCE_LP_RING();
- i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
for (i = 0; i < dma->buf_count; i++) {
struct drm_buf *buf = dma->buflist[i];
@@ -1344,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
dev_priv->page_flipping = 1;
dev_priv->current_page = 0;
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
@@ -1354,7 +1354,7 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (dev_priv->current_page != 0)
i830_dma_dispatch_flip(dev);
@@ -1367,7 +1367,7 @@ static int i830_flip_bufs(struct drm_device *dev, void *data,
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1437,7 +1437,7 @@ static int i830_getparam(struct drm_device *dev, void *data,
int value;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -1464,7 +1464,7 @@ static int i830_setparam(struct drm_device *dev, void *data,
drm_i830_setparam_t *param = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 4caba8c54455..b5bf8cc0fdaa 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -158,7 +158,7 @@ extern int i830_driver_device_is_agp(struct drm_device * dev);
if (I830_VERBOSE) \
printk("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < n*4) \
- i830_wait_ring(dev, n*4, __FUNCTION__); \
+ i830_wait_ring(dev, n*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index a33db5f0967f..91ec2bb497e9 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -58,7 +58,7 @@ static int i830_emit_irq(struct drm_device * dev)
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
atomic_inc(&dev_priv->irq_emitted);
@@ -77,7 +77,7 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr)
unsigned long end = jiffies + HZ * 3;
int ret = 0;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
return 0;
@@ -124,7 +124,7 @@ int i830_irq_emit(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -147,7 +147,7 @@ int i830_irq_wait(struct drm_device *dev, void *data,
drm_i830_irq_wait_t *irqwait = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index ef7bf143a80c..f47e46e3529f 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -194,7 +194,7 @@ static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
@@ -609,7 +609,7 @@ static int i915_quiescent(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index c614d78b3dfd..db7001f22561 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -272,7 +272,7 @@ extern void i915_mem_release(struct drm_device * dev,
if (I915_VERBOSE) \
DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < (n)*4) \
- i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ i915_wait_ring(dev, (n)*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 9072e4a1894e..f6f6c92bf771 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -894,7 +894,7 @@ static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
#if RADEON_FIFO_DEBUG
static void radeon_status(drm_radeon_private_t * dev_priv)
{
- printk("%s:\n", __FUNCTION__);
+ printk("%s:\n", __func__);
printk("RBBM_STATUS = 0x%08x\n",
(unsigned int)RADEON_READ(RADEON_RBBM_STATUS));
printk("CP_RB_RTPR = 0x%08x\n",
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index 59146e3365ba..ea35ab2c9909 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -39,6 +39,7 @@
#include <linux/spinlock.h>
#include <linux/bcd.h>
#include <linux/proc_fs.h>
+#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -451,7 +452,7 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
*/
if (ds1286_is_updating() != 0)
- while (jiffies - uip_watchdog < 2*HZ/100)
+ while (time_before(jiffies, uip_watchdog + 2*HZ/100))
barrier();
/*
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index ffd747c5dff0..60a4df7dac12 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -38,8 +38,8 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include "digiPCI.h"
@@ -73,7 +73,8 @@ static int invalid_lilo_config;
*/
static DEFINE_SPINLOCK(epca_lock);
-/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */
+/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
+ to 7 below. */
static struct board_info boards[MAXBOARDS];
static struct tty_driver *pc_driver;
@@ -157,13 +158,12 @@ static void epca_error(int, char *);
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
static void pc_hangup(struct tty_struct *);
-static void pc_put_char(struct tty_struct *, unsigned char);
static int pc_write_room(struct tty_struct *);
static int pc_chars_in_buffer(struct tty_struct *);
static void pc_flush_buffer(struct tty_struct *);
static void pc_flush_chars(struct tty_struct *);
static int block_til_ready(struct tty_struct *, struct file *,
- struct channel *);
+ struct channel *);
static int pc_open(struct tty_struct *, struct file *);
static void post_fep_init(unsigned int crd);
static void epcapoll(unsigned long);
@@ -175,18 +175,18 @@ static unsigned termios2digi_c(struct channel *ch, unsigned);
static void epcaparam(struct tty_struct *, struct channel *);
static void receive_data(struct channel *);
static int pc_ioctl(struct tty_struct *, struct file *,
- unsigned int, unsigned long);
+ unsigned int, unsigned long);
static int info_ioctl(struct tty_struct *, struct file *,
- unsigned int, unsigned long);
+ unsigned int, unsigned long);
static void pc_set_termios(struct tty_struct *, struct ktermios *);
static void do_softint(struct work_struct *work);
static void pc_stop(struct tty_struct *);
static void pc_start(struct tty_struct *);
-static void pc_throttle(struct tty_struct * tty);
+static void pc_throttle(struct tty_struct *tty);
static void pc_unthrottle(struct tty_struct *tty);
static void digi_send_break(struct channel *ch, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
-void epca_setup(char *, int *);
+static void epca_setup(char *, int *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void);
@@ -243,7 +243,7 @@ static void assertmemoff(struct channel *ch)
/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN|win, b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
static void pcxem_memwinoff(struct board_info *b, unsigned int win)
@@ -253,7 +253,7 @@ static void pcxem_memwinoff(struct board_info *b, unsigned int win)
static void pcxem_globalwinon(struct channel *ch)
{
- outb_p( FEPWIN, (int)ch->board->port + 1);
+ outb_p(FEPWIN, (int)ch->board->port + 1);
}
static void pcxem_rxwinon(struct channel *ch)
@@ -394,7 +394,7 @@ static struct channel *verifyChannel(struct tty_struct *tty)
*/
if (tty) {
struct channel *ch = (struct channel *)tty->driver_data;
- if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
+ if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
if (ch->magic == EPCA_MAGIC)
return ch;
}
@@ -414,7 +414,7 @@ static void pc_sched_event(struct channel *ch, int event)
static void epca_error(int line, char *msg)
{
- printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
+ printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
}
static void pc_close(struct tty_struct *tty, struct file *filp)
@@ -425,7 +425,8 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&epca_lock, flags);
@@ -440,7 +441,6 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
spin_unlock_irqrestore(&epca_lock, flags);
return;
}
-
/* Port open only once go ahead with shutdown & reset */
BUG_ON(ch->count < 0);
@@ -455,12 +455,13 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
spin_unlock_irqrestore(&epca_lock, flags);
if (ch->asyncflags & ASYNC_INITIALIZED) {
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the
+ transmit buffer empties */
setup_empty_event(tty, ch);
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ /* 30 seconds timeout */
+ tty_wait_until_sent(tty, 3000);
}
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
@@ -477,7 +478,7 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&ch->open_wait);
}
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
- ASYNC_CLOSING);
+ ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
}
}
@@ -524,16 +525,15 @@ static void shutdown(struct channel *ch)
static void pc_hangup(struct tty_struct *tty)
{
struct channel *ch;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
@@ -548,7 +548,7 @@ static void pc_hangup(struct tty_struct *tty)
}
static int pc_write(struct tty_struct *tty,
- const unsigned char *buf, int bytesAvailable)
+ const unsigned char *buf, int bytesAvailable)
{
unsigned int head, tail;
int dataLen;
@@ -572,7 +572,8 @@ static int pc_write(struct tty_struct *tty,
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return 0;
/* Make a pointer to the channel data structure found on the board. */
@@ -645,26 +646,19 @@ static int pc_write(struct tty_struct *tty,
return amountCopied;
}
-static void pc_put_char(struct tty_struct *tty, unsigned char c)
-{
- pc_write(tty, &c, 1);
-}
-
static int pc_write_room(struct tty_struct *tty)
{
- int remain;
+ int remain = 0;
struct channel *ch;
unsigned long flags;
unsigned int head, tail;
struct board_chan __iomem *bc;
-
- remain = 0;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
@@ -676,8 +670,8 @@ static int pc_write_room(struct tty_struct *tty)
tail = readw(&bc->tout);
/* Wrap tail if necessary */
tail &= (ch->txbufsize - 1);
-
- if ((remain = tail - head - 1) < 0 )
+ remain = tail - head - 1;
+ if (remain < 0)
remain += ch->txbufsize;
if (remain && (ch->statusflags & LOWWAIT) == 0) {
@@ -699,12 +693,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
struct channel *ch;
struct board_chan __iomem *bc;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return 0;
spin_lock_irqsave(&epca_lock, flags);
@@ -715,7 +709,8 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
head = readw(&bc->tin);
ctail = readw(&ch->mailbox->cout);
- if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
+ if (tail == head && readw(&ch->mailbox->cin) == ctail &&
+ readb(&bc->tbusy) == 0)
chars = 0;
else { /* Begin if some space on the card has been used */
head = readw(&bc->tin) & (ch->txbufsize - 1);
@@ -725,7 +720,8 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
* pc_write_room here we are finding the amount of bytes in the
* buffer filled. Not the amount of bytes empty.
*/
- if ((remain = tail - head - 1) < 0 )
+ remain = tail - head - 1;
+ if (remain < 0)
remain += ch->txbufsize;
chars = (int)(ch->txbufsize - remain);
/*
@@ -736,7 +732,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
* transmit buffer empties.
*/
if (!(ch->statusflags & EMPTYWAIT))
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
} /* End if some space on the card has been used */
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -754,7 +750,8 @@ static void pc_flush_buffer(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return;
spin_lock_irqsave(&epca_lock, flags);
@@ -775,23 +772,25 @@ static void pc_flush_chars(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
/*
* If not already set and the transmitter is busy setup an
* event to indicate when the transmit empties.
*/
- if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
- setup_empty_event(tty,ch);
+ if ((ch->statusflags & TXBUSY) &&
+ !(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
}
}
static int block_til_ready(struct tty_struct *tty,
- struct file *filp, struct channel *ch)
+ struct file *filp, struct channel *ch)
{
- DECLARE_WAITQUEUE(wait,current);
+ DECLARE_WAITQUEUE(wait, current);
int retval, do_clocal = 0;
unsigned long flags;
@@ -839,8 +838,7 @@ static int block_til_ready(struct tty_struct *tty,
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED))
- {
+ !(ch->asyncflags & ASYNC_INITIALIZED)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
@@ -880,7 +878,7 @@ static int block_til_ready(struct tty_struct *tty,
return 0;
}
-static int pc_open(struct tty_struct *tty, struct file * filp)
+static int pc_open(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
unsigned long flags;
@@ -923,7 +921,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
return(-ENODEV);
}
- if ((bc = ch->brdchan) == 0) {
+ bc = ch->brdchan;
+ if (bc == NULL) {
tty->driver_data = NULL;
return -ENODEV;
}
@@ -964,7 +963,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -1002,8 +1001,8 @@ static void __exit epca_module_exit(void)
del_timer_sync(&epca_timer);
- if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))
- {
+ if (tty_unregister_driver(pc_driver) ||
+ tty_unregister_driver(pc_info)) {
printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
}
@@ -1034,7 +1033,6 @@ static const struct tty_operations pc_ops = {
.flush_buffer = pc_flush_buffer,
.chars_in_buffer = pc_chars_in_buffer,
.flush_chars = pc_flush_chars,
- .put_char = pc_put_char,
.ioctl = pc_ioctl,
.set_termios = pc_set_termios,
.stop = pc_stop,
@@ -1044,7 +1042,7 @@ static const struct tty_operations pc_ops = {
.hangup = pc_hangup,
};
-static int info_open(struct tty_struct *tty, struct file * filp)
+static int info_open(struct tty_struct *tty, struct file *filp)
{
return 0;
}
@@ -1099,7 +1097,7 @@ static int __init pc_init(void)
* Set up interrupt, we will worry about memory allocation in
* post_fep_init.
*/
- printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
+ printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
/*
* NOTE : This code assumes that the number of ports found in the
@@ -1252,7 +1250,7 @@ static int __init pc_init(void)
if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000;
} else
- printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n", (int)bd->port);
break;
}
}
@@ -1326,12 +1324,12 @@ static void post_fep_init(unsigned int crd)
*/
/* PCI cards are already remapped at this point ISA are not */
bd->numports = readw(bd->re_map_membase + XEMPORTS);
- epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
+ epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
nbdevs += (bd->numports);
} else {
/* Fix up the mappings for ISA/EISA etc */
/* FIXME: 64K - can we be smarter ? */
- bd->re_map_membase = ioremap(bd->membase, 0x10000);
+ bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
}
if (crd != 0)
@@ -1362,7 +1360,8 @@ static void post_fep_init(unsigned int crd)
* XEPORTS (address 0xc22) points at the number of channels the card
* supports. (For 64XE, XI, XEM, and XR use 0xc02)
*/
- if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
+ if ((bd->type == PCXEVE || bd->type == PCXE) &&
+ (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1;
if (bd->type < PCIXEM)
if (!request_region((int)bd->port, 4, board_desc[bd->type]))
@@ -1461,10 +1460,12 @@ static void post_fep_init(unsigned int crd)
case PCXEVE:
case PCXE:
- ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
+ & 0x1fff);
ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
- ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
- ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
+ ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
+ & 0x1fff);
+ ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
break;
case PCXI:
@@ -1518,8 +1519,9 @@ static void post_fep_init(unsigned int crd)
}
printk(KERN_INFO
- "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
- VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ VERSION, board_desc[bd->type], (long)bd->port,
+ (long)bd->membase, bd->numports);
memwinoff(bd, 0);
}
@@ -1527,7 +1529,7 @@ static void epcapoll(unsigned long ignored)
{
unsigned long flags;
int crd;
- volatile unsigned int head, tail;
+ unsigned int head, tail;
struct channel *ch;
struct board_info *bd;
@@ -1593,7 +1595,9 @@ static void doevent(int crd)
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
assertgwinon(chan0);
- while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */
+ while ((tail = readw(&chan0->mailbox->eout)) !=
+ (head = readw(&chan0->mailbox->ein))) {
+ /* Begin while something in event queue */
assertgwinon(chan0);
eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
@@ -1617,7 +1621,8 @@ static void doevent(int crd)
goto next;
}
- if ((bc = ch->brdchan) == NULL)
+ bc = ch->brdchan;
+ if (bc == NULL)
goto next;
if (event & DATA_IND) { /* Begin DATA_IND */
@@ -1629,10 +1634,11 @@ static void doevent(int crd)
/* A modem signal change has been indicated */
ch->imodem = mstat;
if (ch->asyncflags & ASYNC_CHECK_CD) {
- if (mstat & ch->dcd) /* We are now receiving dcd */
+ /* We are now receiving dcd */
+ if (mstat & ch->dcd)
wake_up_interruptible(&ch->open_wait);
- else
- pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
+ else /* No dcd; hangup */
+ pc_sched_event(ch, EPCA_EVENT_HANGUP);
}
}
tty = ch->tty;
@@ -1647,7 +1653,8 @@ static void doevent(int crd)
tty_wakeup(tty);
}
} else if (event & EMPTYTX_IND) {
- /* This event is generated by setup_empty_event */
+ /* This event is generated by
+ setup_empty_event */
ch->statusflags &= ~TXBUSY;
if (ch->statusflags & EMPTYWAIT) {
ch->statusflags &= ~EMPTYWAIT;
@@ -1655,7 +1662,7 @@ static void doevent(int crd)
}
}
}
- next:
+next:
globalwinon(ch);
BUG_ON(!bc);
writew(1, &bc->idata);
@@ -1665,7 +1672,7 @@ static void doevent(int crd)
}
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
- int byte2, int ncmds, int bytecmd)
+ int byte2, int ncmds, int bytecmd)
{
unchar __iomem *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
@@ -1690,8 +1697,10 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
memaddr = ch->board->re_map_membase;
if (head >= (cmdMax - cmdStart) || (head & 03)) {
- printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head);
- printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart);
+ printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
+ __LINE__, cmd, head);
+ printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
+ __LINE__, cmdMax, cmdStart);
return;
}
if (bytecmd) {
@@ -1770,7 +1779,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
{
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
- INPCK | ISTRIP|IXON|IXANY|IXOFF);
+ INPCK | ISTRIP | IXON | IXANY | IXOFF);
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
@@ -1838,7 +1847,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
unsigned mval, hflow, cflag, iflag;
bc = ch->brdchan;
- epcaassert(bc !=0, "bc out of range");
+ epcaassert(bc != NULL, "bc out of range");
assertgwinon(ch);
ts = tty->termios;
@@ -1884,8 +1893,10 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* Command sets channels iflag structure on the board. Such
* things as input soft flow control, handling of parity
* errors, and break handling are all set here.
+ *
+ * break handling, parity handling, input stripping,
+ * flow control chars
*/
- /* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
/*
@@ -1981,7 +1992,7 @@ static void receive_data(struct channel *ch)
return;
/* If CREAD bit is off or device not open, set TX tail to head */
- if (!tty || !ts || !(ts->c_cflag & CREAD)) {
+ if (!tty || !ts || !(ts->c_cflag & CREAD)) {
writew(head, &bc->rout);
return;
}
@@ -1991,18 +2002,21 @@ static void receive_data(struct channel *ch)
if (readb(&bc->orun)) {
writeb(0, &bc->orun);
- printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
+ printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
+ tty->name);
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
rxwinon(ch);
- while (bytesAvailable > 0) { /* Begin while there is data on the card */
+ while (bytesAvailable > 0) {
+ /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
/*
* Even if head has wrapped around only report the amount of
* data to be equal to the size - tail. Remember memcpy can't
* automaticly wrap around the receive buffer.
*/
- dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
+ dataToRead = (wrapgap < bytesAvailable) ? wrapgap
+ : bytesAvailable;
/* Make sure we don't overflow the buffer */
dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
if (dataToRead == 0)
@@ -2153,14 +2167,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
return 0;
}
-static int pc_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int pc_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
digiflow_t dflow;
int retval;
@@ -2175,7 +2189,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
bc = ch->brdchan;
else
return -EINVAL;
-
/*
* For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
* /usr/src/linux/drivers/char for a good example. In particular think
@@ -2186,9 +2199,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
retval = tty_check_change(tty);
if (retval)
return retval;
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit
+ buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
if (!arg)
@@ -2198,29 +2212,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
retval = tty_check_change(tty);
if (retval)
return retval;
-
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit buffer
+ empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
return 0;
- case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
- return -EFAULT;
- return 0;
- case TIOCSSOFTCAR:
- {
- unsigned int value;
-
- if (get_user(value, (unsigned __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (value ? CLOCAL : 0));
- return 0;
- }
case TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
@@ -2253,10 +2252,12 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
break;
case DIGI_SETAW:
case DIGI_SETAF:
+ lock_kernel();
if (cmd == DIGI_SETAW) {
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit
+ buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
} else {
@@ -2264,6 +2265,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
}
+ unlock_kernel();
/* Fall Thru */
case DIGI_SETA:
if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
@@ -2285,7 +2287,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
* control issues, etc.... It effect both control flags and
* input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
break;
@@ -2321,18 +2323,21 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
if (copy_from_user(&dflow, argp, sizeof(dflow)))
return -EFAULT;
- if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
+ if (dflow.startc != startc || dflow.stopc != stopc) {
+ /* Begin if setflow toggled */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
if (cmd == DIGI_SETFLOW) {
ch->fepstartc = ch->startc = dflow.startc;
ch->fepstopc = ch->stopc = dflow.stopc;
- fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
+ fepcmd(ch, SONOFFC, ch->fepstartc,
+ ch->fepstopc, 0, 1);
} else {
ch->fepstartca = ch->startca = dflow.startc;
ch->fepstopca = ch->stopca = dflow.stopc;
- fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca,
+ ch->fepstopca, 0, 1);
}
if (ch->statusflags & TXSTOPPED)
@@ -2356,7 +2361,9 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ ch = verifyChannel(tty);
+
+ if (ch != NULL) { /* Begin if channel valid */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
epcaparam(tty, ch);
@@ -2383,7 +2390,7 @@ static void do_softint(struct work_struct *work)
if (tty && tty->driver_data) {
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
- tty_hangup(tty); /* FIXME: module removal race here - AKPM */
+ tty_hangup(tty);
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
}
@@ -2403,9 +2410,11 @@ static void pc_stop(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
- if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
+ if ((ch->statusflags & TXSTOPPED) == 0) {
+ /* Begin if transmit stop requested */
globalwinon(ch);
/* STOP transmitting now !! */
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
@@ -2423,11 +2432,14 @@ static void pc_start(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
- /* Just in case output was resumed because of a change in Digi-flow */
- if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */
+ /* Just in case output was resumed because of a change
+ in Digi-flow */
+ if (ch->statusflags & TXSTOPPED) {
+ /* Begin transmit resume requested */
struct board_chan __iomem *bc;
globalwinon(ch);
bc = ch->brdchan;
@@ -2457,7 +2469,8 @@ static void pc_throttle(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
@@ -2477,8 +2490,10 @@ static void pc_unthrottle(struct tty_struct *tty)
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
- /* Just in case output was resumed because of a change in Digi-flow */
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
+ /* Just in case output was resumed because of a change
+ in Digi-flow */
spin_lock_irqsave(&epca_lock, flags);
if (ch->statusflags & RXSTOPPED) {
globalwinon(ch);
@@ -2490,7 +2505,7 @@ static void pc_unthrottle(struct tty_struct *tty)
}
}
-void digi_send_break(struct channel *ch, int msec)
+static void digi_send_break(struct channel *ch, int msec)
{
unsigned long flags;
@@ -2523,7 +2538,7 @@ static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
memoff(ch);
}
-void epca_setup(char *str, int *ints)
+static void epca_setup(char *str, int *ints)
{
struct board_info board;
int index, loop, last;
@@ -2552,14 +2567,16 @@ void epca_setup(char *str, int *ints)
* instructing the driver to ignore epcaconfig.) For
* this reason we check for 2.
*/
- if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
+ if (board.status == 2) {
+ /* Begin ignore epcaconfig as well as lilo cmd line */
nbdevs = 0;
num_cards = 0;
return;
} /* End ignore epcaconfig as well as lilo cmd line */
if (board.status > 2) {
- printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
+ board.status);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
@@ -2613,7 +2630,8 @@ void epca_setup(char *str, int *ints)
case 6:
board.membase = ints[index];
if (ints[index] <= 0) {
- printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
+ (unsigned int)board.membase);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -2744,7 +2762,7 @@ void epca_setup(char *str, int *ints)
t2++;
if (*t2) {
- printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -2766,7 +2784,7 @@ void epca_setup(char *str, int *ints)
/* I should REALLY validate the stuff here */
/* Copies our local copy of board into boards */
- memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
+ memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
/* Does this get called once per lilo arg are what ? */
printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
num_cards, board_desc[board.type],
@@ -2807,9 +2825,9 @@ static int __devinit epca_init_one(struct pci_dev *pdev,
if (board_idx >= MAXBOARDS)
goto err_out;
- addr = pci_resource_start (pdev, epca_info_tbl[info_idx].bar_idx);
+ addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
if (!addr) {
- printk (KERN_ERR PFX "PCI region #%d not available (size 0)\n",
+ printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
epca_info_tbl[info_idx].bar_idx);
goto err_out;
}
@@ -2820,28 +2838,29 @@ static int __devinit epca_init_one(struct pci_dev *pdev,
boards[board_idx].port = addr + PCI_IO_OFFSET;
boards[board_idx].membase = addr;
- if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
- printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
+ if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
+ printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out;
}
- boards[board_idx].re_map_port = ioremap(addr + PCI_IO_OFFSET, 0x200000);
+ boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
+ 0x200000);
if (!boards[board_idx].re_map_port) {
- printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
+ printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out_free_pciio;
}
- if (!request_mem_region (addr, 0x200000, "epca")) {
- printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
+ if (!request_mem_region(addr, 0x200000, "epca")) {
+ printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
0x200000, addr);
goto err_out_free_iounmap;
}
- boards[board_idx].re_map_membase = ioremap(addr, 0x200000);
+ boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
if (!boards[board_idx].re_map_membase) {
- printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
+ printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out_free_memregion;
}
@@ -2858,11 +2877,11 @@ static int __devinit epca_init_one(struct pci_dev *pdev,
return 0;
err_out_free_memregion:
- release_mem_region (addr, 0x200000);
+ release_mem_region(addr, 0x200000);
err_out_free_iounmap:
- iounmap (boards[board_idx].re_map_port);
+ iounmap(boards[board_idx].re_map_port);
err_out_free_pciio:
- release_mem_region (addr + PCI_IO_OFFSET, 0x200000);
+ release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
err_out:
return -ENODEV;
}
@@ -2878,9 +2897,9 @@ static struct pci_device_id epca_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
-int __init init_PCI (void)
+static int __init init_PCI(void)
{
- memset (&epca_driver, 0, sizeof (epca_driver));
+ memset(&epca_driver, 0, sizeof(epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
epca_driver.probe = epca_init_one;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index f3fe62067344..84840ba13ff0 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -8,7 +8,7 @@
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
* 16450/16550A UART's. Added support for the AST FourPort and the
- * Accent Async board.
+ * Accent Async board.
*
* set_serial_info fixed to set the flags, custom divisor, and uart
* type fields. Fix suggested by Michael K. Johnson 12/12/92.
@@ -61,11 +61,11 @@
#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/hayesesp.h>
@@ -127,8 +127,10 @@ static struct tty_driver *esp_driver;
#undef SERIAL_DEBUG_FLOW
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s)
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ tty->name, info->flags, \
+ serial_driver.refcount, \
+ info->count, tty->count, s)
#else
#define DBG_CNT(s)
#endif
@@ -189,7 +191,7 @@ static inline void serial_out(struct esp_struct *info, int offset,
*/
static void rs_stop(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
@@ -206,12 +208,12 @@ static void rs_stop(struct tty_struct *tty)
static void rs_start(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
@@ -233,7 +235,7 @@ static void rs_start(struct tty_struct *tty)
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
- *
+ *
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
@@ -290,7 +292,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
}
status_mask = (info->read_status_mask >> 2) & 0x07;
-
+
for (i = 0; i < num_bytes - 1; i += 2) {
*((unsigned short *)(pio_buf->data + i)) =
inw(info->port + UART_ESI_RX);
@@ -325,8 +327,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
flag = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
- }
- else if (err_buf->data[i] & 0x02)
+ } else if (err_buf->data[i] & 0x02)
flag = TTY_FRAME;
else if (err_buf->data[i] & 0x01)
flag = TTY_PARITY;
@@ -341,23 +342,29 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
release_pio_buffer(err_buf);
}
-static inline void receive_chars_dma(struct esp_struct *info, int num_bytes)
+static void program_isa_dma(int dma, int dir, unsigned long addr, int len)
{
unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(dma);
+ clear_dma_ff(dma);
+ set_dma_mode(dma, dir);
+ set_dma_addr(dma, addr);
+ set_dma_count(dma, len);
+ enable_dma(dma);
+ release_dma_lock(flags);
+}
+
+static void receive_chars_dma(struct esp_struct *info, int num_bytes)
+{
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
dma_bytes = num_bytes;
info->stat_flags |= ESP_STAT_DMA_RX;
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_READ);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
+
+ program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer),
+ dma_bytes);
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
}
static inline void receive_chars_dma_done(struct esp_struct *info,
@@ -366,22 +373,22 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
struct tty_struct *tty = info->tty;
int num_bytes;
unsigned long flags;
-
- flags=claim_dma_lock();
+
+ flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
info->stat_flags &= ~ESP_STAT_DMA_RX;
num_bytes = dma_bytes - get_dma_residue(dma);
release_dma_lock(flags);
-
+
info->icount.rx += num_bytes;
if (num_bytes > 0) {
tty_insert_flip_string(tty, dma_buffer, num_bytes - 1);
status &= (0x1c & info->read_status_mask);
-
+
/* Is the status significant or do we throw the last byte ? */
if (!(status & info->ignore_status_mask)) {
int statflag = 0;
@@ -393,13 +400,13 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
do_SAK(tty);
} else if (status & 0x08) {
statflag = TTY_FRAME;
- (info->icount.frame)++;
- }
- else if (status & 0x04) {
+ info->icount.frame++;
+ } else if (status & 0x04) {
statflag = TTY_PARITY;
- (info->icount.parity)++;
+ info->icount.parity++;
}
- tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
+ tty_insert_flip_char(tty, dma_buffer[num_bytes - 1],
+ statflag);
}
tty_schedule_flip(tty);
}
@@ -484,8 +491,6 @@ static inline void transmit_chars_pio(struct esp_struct *info,
/* Caller must hold info->lock */
static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
{
- unsigned long flags;
-
dma_bytes = num_bytes;
if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
@@ -517,26 +522,18 @@ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
}
info->stat_flags |= ESP_STAT_DMA_TX;
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_WRITE);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
+
+ program_isa_dma(dma, DMA_MODE_WRITE, isa_virt_to_bus(dma_buffer),
+ dma_bytes);
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
}
static inline void transmit_chars_dma_done(struct esp_struct *info)
{
int num_bytes;
unsigned long flags;
-
- flags=claim_dma_lock();
+ flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
@@ -547,27 +544,21 @@ static inline void transmit_chars_dma_done(struct esp_struct *info)
if (dma_bytes != num_bytes) {
dma_bytes -= num_bytes;
memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes);
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_WRITE);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
+
+ program_isa_dma(dma, DMA_MODE_WRITE,
+ isa_virt_to_bus(dma_buffer), dma_bytes);
+
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
} else {
dma_bytes = 0;
info->stat_flags &= ~ESP_STAT_DMA_TX;
}
}
-static inline void check_modem_status(struct esp_struct *info)
+static void check_modem_status(struct esp_struct *info)
{
int status;
-
+
serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
status = serial_in(info, UART_ESI_STAT2);
@@ -588,7 +579,7 @@ static inline void check_modem_status(struct esp_struct *info)
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
-#endif
+#endif
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
else {
@@ -605,7 +596,7 @@ static inline void check_modem_status(struct esp_struct *info)
*/
static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{
- struct esp_struct * info;
+ struct esp_struct *info;
unsigned err_status;
unsigned int scratch;
@@ -617,7 +608,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
scratch = serial_in(info, UART_ESI_SID);
spin_lock(&info->lock);
-
+
if (!info->tty) {
spin_unlock(&info->lock);
return IRQ_NONE;
@@ -637,7 +628,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
if (err_status & 0x80) /* Start break */
wake_up_interruptible(&info->break_wait);
}
-
+
if ((scratch & 0x88) || /* DMA completed or timed out */
(err_status & 0x1c) /* receive error */) {
if (info->stat_flags & ESP_STAT_DMA_RX)
@@ -667,7 +658,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
receive_chars_dma(info, num_bytes);
}
}
-
+
if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
(scratch & 0x02) && (info->IER & UART_IER_THRI)) {
if ((info->xmit_cnt <= 0) || info->tty->stopped) {
@@ -722,11 +713,11 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
* ---------------------------------------------------------------
*/
-static inline void esp_basic_init(struct esp_struct * info)
+static void esp_basic_init(struct esp_struct *info)
{
/* put ESPC in enhanced mode */
serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
-
+
if (info->stat_flags & ESP_STAT_NEVER_DMA)
serial_out(info, UART_ESI_CMD2, 0x01);
else
@@ -783,13 +774,13 @@ static inline void esp_basic_init(struct esp_struct * info)
serial_out(info, UART_ESI_CMD2, 0xff);
}
-static int startup(struct esp_struct * info)
+static int startup(struct esp_struct *info)
{
unsigned long flags;
- int retval=0;
- unsigned int num_chars;
+ int retval = 0;
+ unsigned int num_chars;
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->flags & ASYNC_INITIALIZED)
goto out;
@@ -802,7 +793,8 @@ static int startup(struct esp_struct * info)
}
#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+ printk(KERN_DEBUG "starting up ttys%d (irq %d)...",
+ info->line, info->irq);
#endif
/* Flush the RX buffer. Using the ESI flush command may cause */
@@ -863,7 +855,7 @@ static int startup(struct esp_struct * info)
dma_buffer = NULL;
info->stat_flags |= ESP_STAT_USE_PIO;
}
-
+
}
info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
@@ -872,7 +864,7 @@ static int startup(struct esp_struct * info)
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR);
-
+
/*
* Finally, enable interrupts
*/
@@ -881,7 +873,7 @@ static int startup(struct esp_struct * info)
UART_IER_DMA_TC;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
-
+
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
@@ -900,7 +892,7 @@ static int startup(struct esp_struct * info)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
-
+
/*
* set the speed of the serial port
*/
@@ -918,7 +910,7 @@ out_unlocked:
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct esp_struct * info)
+static void shutdown(struct esp_struct *info)
{
unsigned long flags, f;
@@ -929,7 +921,7 @@ static void shutdown(struct esp_struct * info)
printk("Shutting down serial port %d (irq %d)....", info->line,
info->irq);
#endif
-
+
spin_lock_irqsave(&info->lock, flags);
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
@@ -941,14 +933,14 @@ static void shutdown(struct esp_struct * info)
/* stop a DMA transfer on the port being closed */
/* DMA lock is higher priority always */
if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
- f=claim_dma_lock();
+ f = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
release_dma_lock(f);
-
+
dma_bytes = 0;
}
-
+
/*
* Free the IRQ
*/
@@ -970,7 +962,7 @@ static void shutdown(struct esp_struct * info)
free_pages((unsigned long)dma_buffer,
get_order(DMA_BUFFER_SZ));
dma_buffer = NULL;
- }
+ }
}
if (info->xmit_buf) {
@@ -992,7 +984,7 @@ static void shutdown(struct esp_struct * info)
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
-
+
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&info->lock, flags);
}
@@ -1005,7 +997,7 @@ static void change_speed(struct esp_struct *info)
{
unsigned short port;
int quot = 0;
- unsigned cflag,cval;
+ unsigned cflag, cval;
int baud, bits;
unsigned char flow1 = 0, flow2 = 0;
unsigned long flags;
@@ -1014,14 +1006,14 @@ static void change_speed(struct esp_struct *info)
return;
cflag = info->tty->termios->c_cflag;
port = info->port;
-
+
/* byte size and parity */
switch (cflag & CSIZE) {
- case CS5: cval = 0x00; bits = 7; break;
- case CS6: cval = 0x01; bits = 8; break;
- case CS7: cval = 0x02; bits = 9; break;
- case CS8: cval = 0x03; bits = 10; break;
- default: cval = 0x00; bits = 7; break;
+ case CS5: cval = 0x00; bits = 7; break;
+ case CS6: cval = 0x01; bits = 8; break;
+ case CS7: cval = 0x02; bits = 9; break;
+ case CS8: cval = 0x03; bits = 10; break;
+ default: cval = 0x00; bits = 7; break;
}
if (cflag & CSTOPB) {
cval |= 0x04;
@@ -1037,14 +1029,12 @@ static void change_speed(struct esp_struct *info)
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
-
baud = tty_get_baud_rate(info->tty);
if (baud == 38400 &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->custom_divisor;
else {
- if (baud == 134)
- /* Special case since 134 is really 134.5 */
+ if (baud == 134) /* Special case since 134 is really 134.5 */
quot = (2*BASE_BAUD / 269);
else if (baud)
quot = BASE_BAUD / baud;
@@ -1052,7 +1042,12 @@ static void change_speed(struct esp_struct *info)
/* If the quotient is ever zero, default to 9600 bps */
if (!quot)
quot = BASE_BAUD / 9600;
-
+
+ if (baud) {
+ /* Actual rate */
+ baud = BASE_BAUD/quot;
+ tty_encode_baud_rate(info->tty, baud, baud);
+ }
info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);
/* CTS flow control flag and modem status interrupts */
@@ -1066,10 +1061,8 @@ static void change_speed(struct esp_struct *info)
info->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
- else {
+ else
info->flags |= ASYNC_CHECK_CD;
- /* info->IER |= UART_IER_MSI; */
- }
/*
* Set up parity check flag
@@ -1079,7 +1072,7 @@ static void change_speed(struct esp_struct *info)
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= UART_LSR_BI;
-
+
info->ignore_status_mask = 0;
#if 0
/* This should be safe, but for some broken bits of hardware... */
@@ -1092,7 +1085,7 @@ static void change_speed(struct esp_struct *info)
info->ignore_status_mask |= UART_LSR_BI;
info->read_status_mask |= UART_LSR_BI;
/*
- * If we're ignore parity and break indicators, ignore
+ * If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty)) {
@@ -1130,19 +1123,19 @@ static void change_speed(struct esp_struct *info)
serial_out(info, UART_ESI_CMD2, 0x10);
serial_out(info, UART_ESI_CMD2, 0x21);
switch (cflag & CSIZE) {
- case CS5:
- serial_out(info, UART_ESI_CMD2, 0x1f);
- break;
- case CS6:
- serial_out(info, UART_ESI_CMD2, 0x3f);
- break;
- case CS7:
- case CS8:
- serial_out(info, UART_ESI_CMD2, 0x7f);
- break;
- default:
- serial_out(info, UART_ESI_CMD2, 0xff);
- break;
+ case CS5:
+ serial_out(info, UART_ESI_CMD2, 0x1f);
+ break;
+ case CS6:
+ serial_out(info, UART_ESI_CMD2, 0x3f);
+ break;
+ case CS7:
+ case CS8:
+ serial_out(info, UART_ESI_CMD2, 0x7f);
+ break;
+ default:
+ serial_out(info, UART_ESI_CMD2, 0xff);
+ break;
}
}
@@ -1156,31 +1149,34 @@ static void change_speed(struct esp_struct *info)
spin_unlock_irqrestore(&info->lock, flags);
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= ESP_XMIT_SIZE-1;
info->xmit_cnt++;
+ ret = 1;
}
spin_unlock_irqrestore(&info->lock, flags);
+ return ret;
}
static void rs_flush_chars(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
return;
@@ -1198,11 +1194,11 @@ out:
spin_unlock_irqrestore(&info->lock, flags);
}
-static int rs_write(struct tty_struct * tty,
+static int rs_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
int c, t, ret = 0;
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_write"))
@@ -1210,19 +1206,19 @@ static int rs_write(struct tty_struct * tty,
if (!info->xmit_buf)
return 0;
-
+
while (1) {
/* Thanks to R. Wolff for suggesting how to do this with */
/* interrupts enabled */
c = count;
t = ESP_XMIT_SIZE - info->xmit_cnt - 1;
-
+
if (t < c)
c = t;
t = ESP_XMIT_SIZE - info->xmit_head;
-
+
if (t < c)
c = t;
@@ -1252,10 +1248,10 @@ static int rs_write(struct tty_struct * tty,
static int rs_write_room(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
int ret;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
@@ -1270,8 +1266,8 @@ static int rs_write_room(struct tty_struct *tty)
static int rs_chars_in_buffer(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
-
+ struct esp_struct *info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
return info->xmit_cnt;
@@ -1279,9 +1275,9 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_flush_buffer(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
spin_lock_irqsave(&info->lock, flags);
@@ -1293,20 +1289,20 @@ static void rs_flush_buffer(struct tty_struct *tty)
/*
* ------------------------------------------------------------
* rs_throttle()
- *
+ *
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
-static void rs_throttle(struct tty_struct * tty)
+static void rs_throttle(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
+
printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
+ tty_chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
@@ -1321,20 +1317,20 @@ static void rs_throttle(struct tty_struct * tty)
spin_unlock_irqrestore(&info->lock, flags);
}
-static void rs_unthrottle(struct tty_struct * tty)
+static void rs_unthrottle(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
- printk("unthrottle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
+
+ printk(KERN_DEBUG "unthrottle %s: %d....\n", tty_name(tty, buf),
+ tty_chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
info->IER |= UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
@@ -1350,11 +1346,12 @@ static void rs_unthrottle(struct tty_struct * tty)
* ------------------------------------------------------------
*/
-static int get_serial_info(struct esp_struct * info,
+static int get_serial_info(struct esp_struct *info,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
-
+
+ lock_kernel();
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
tmp.line = info->line;
@@ -1367,20 +1364,22 @@ static int get_serial_info(struct esp_struct * info,
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = 0;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ unlock_kernel();
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
}
-static int get_esp_config(struct esp_struct * info,
+static int get_esp_config(struct esp_struct *info,
struct hayes_esp_config __user *retinfo)
{
struct hayes_esp_config tmp;
-
+
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.rx_timeout = info->config.rx_timeout;
tmp.rx_trigger = info->config.rx_trigger;
tmp.tx_trigger = info->config.tx_trigger;
@@ -1388,11 +1387,12 @@ static int get_esp_config(struct esp_struct * info,
tmp.flow_on = info->config.flow_on;
tmp.pio_threshold = info->config.pio_threshold;
tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma);
+ unlock_kernel();
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
-static int set_serial_info(struct esp_struct * info,
+static int set_serial_info(struct esp_struct *info,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
@@ -1401,7 +1401,7 @@ static int set_serial_info(struct esp_struct * info,
int retval = 0;
struct esp_struct *current_async;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
old_info = *info;
@@ -1422,7 +1422,7 @@ static int set_serial_info(struct esp_struct * info,
return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) {
- if (change_irq ||
+ if (change_irq ||
(new_serial.close_delay != info->close_delay) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->flags & ~ASYNC_USR_MASK)))
@@ -1507,8 +1507,8 @@ static int set_serial_info(struct esp_struct * info,
return retval;
}
-static int set_esp_config(struct esp_struct * info,
- struct hayes_esp_config __user * new_info)
+static int set_esp_config(struct esp_struct *info,
+ struct hayes_esp_config __user *new_info)
{
struct hayes_esp_config new_config;
unsigned int change_dma;
@@ -1550,7 +1550,6 @@ static int set_esp_config(struct esp_struct * info,
if (new_config.dma_channel) {
/* PIO mode to DMA mode transition OR */
/* change current DMA channel */
-
current_async = ports;
while (current_async) {
@@ -1559,16 +1558,15 @@ static int set_esp_config(struct esp_struct * info,
return -EBUSY;
} else if (current_async->count)
return -EBUSY;
-
- current_async =
- current_async->next_port;
+
+ current_async = current_async->next_port;
}
shutdown(info);
dma = new_config.dma_channel;
info->stat_flags &= ~ESP_STAT_NEVER_DMA;
-
- /* all ports must use the same DMA channel */
+
+ /* all ports must use the same DMA channel */
spin_lock_irqsave(&info->lock, flags);
current_async = ports;
@@ -1580,7 +1578,6 @@ static int set_esp_config(struct esp_struct * info,
spin_unlock_irqrestore(&info->lock, flags);
} else {
/* DMA mode to PIO mode only */
-
if (info->count > 1)
return -EBUSY;
@@ -1596,8 +1593,6 @@ static int set_esp_config(struct esp_struct * info,
if ((new_config.flow_off != info->config.flow_off) ||
(new_config.flow_on != info->config.flow_on)) {
- unsigned long flags;
-
info->config.flow_off = new_config.flow_off;
info->config.flow_on = new_config.flow_on;
@@ -1612,8 +1607,6 @@ static int set_esp_config(struct esp_struct * info,
if ((new_config.rx_trigger != info->config.rx_trigger) ||
(new_config.tx_trigger != info->config.tx_trigger)) {
- unsigned long flags;
-
info->config.rx_trigger = new_config.rx_trigger;
info->config.tx_trigger = new_config.tx_trigger;
spin_lock_irqsave(&info->lock, flags);
@@ -1628,8 +1621,6 @@ static int set_esp_config(struct esp_struct * info,
}
if (new_config.rx_timeout != info->config.rx_timeout) {
- unsigned long flags;
-
info->config.rx_timeout = new_config.rx_timeout;
spin_lock_irqsave(&info->lock, flags);
@@ -1657,9 +1648,9 @@ static int set_esp_config(struct esp_struct * info,
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
+ * allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
+static int get_lsr_info(struct esp_struct *info, unsigned int __user *value)
{
unsigned char status;
unsigned int result;
@@ -1670,17 +1661,17 @@ static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
status = serial_in(info, UART_ESI_STAT1);
spin_unlock_irqrestore(&info->lock, flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
+ return put_user(result, value);
}
static int esp_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned char control, status;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1703,10 +1694,10 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file)
static int esp_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1736,9 +1727,9 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
*/
static void esp_break(struct tty_struct *tty, int break_state)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "esp_break"))
return;
@@ -1758,14 +1749,15 @@ static void esp_break(struct tty_struct *tty, int break_state)
}
}
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
+static int rs_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg;
unsigned long flags;
+ int ret;
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
@@ -1778,97 +1770,93 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(info, argp);
- case TIOCSSERIAL:
- return set_serial_info(info, argp);
- case TIOCSERCONFIG:
- /* do not reconfigure after initial configuration */
- return 0;
-
- case TIOCSERGWILD:
- return put_user(0L, (unsigned long __user *)argp);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, argp);
-
- case TIOCSERSWILD:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- return 0;
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ lock_kernel();
+ ret = set_serial_info(info, argp);
+ unlock_kernel();
+ return ret;
+ case TIOCSERGWILD:
+ return put_user(0L, (unsigned long __user *)argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, argp);
+ case TIOCSERSWILD:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ spin_lock_irqsave(&info->lock, flags);
+ cprev = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->lock, flags);
+ while (1) {
+ /* FIXME: convert to new style wakeup */
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
spin_lock_irqsave(&info->lock, flags);
- cprev = info->icount; /* note the counters on entry */
+ cnow = info->icount; /* atomic copy */
spin_unlock_irqrestore(&info->lock, flags);
- while (1) {
- /* FIXME: convert to new style wakeup */
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irqsave(&info->lock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->lock, flags);
- if (cnow.rng == cprev.rng &&
- cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd &&
- cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) &&
- (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) &&
- (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) &&
- (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) &&
- (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
+ if (cnow.rng == cprev.rng &&
+ cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd &&
+ cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) &&
+ (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) &&
+ (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) &&
+ (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) &&
+ (cnow.cts != cprev.cts))) {
+ return 0;
}
- /* NOTREACHED */
-
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- case TIOCGICOUNT:
- spin_lock_irqsave(&info->lock, flags);
- cnow = info->icount;
- spin_unlock_irqrestore(&info->lock, flags);
- p_cuser = argp;
- if (put_user(cnow.cts, &p_cuser->cts) ||
- put_user(cnow.dsr, &p_cuser->dsr) ||
- put_user(cnow.rng, &p_cuser->rng) ||
- put_user(cnow.dcd, &p_cuser->dcd))
- return -EFAULT;
-
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->lock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->lock, flags);
+ p_cuser = argp;
+ if (put_user(cnow.cts, &p_cuser->cts) ||
+ put_user(cnow.dsr, &p_cuser->dsr) ||
+ put_user(cnow.rng, &p_cuser->rng) ||
+ put_user(cnow.dcd, &p_cuser->dcd))
+ return -EFAULT;
return 0;
case TIOCGHAYESESP:
return get_esp_config(info, argp);
case TIOCSHAYESESP:
- return set_esp_config(info, argp);
-
- default:
- return -ENOIOCTLCMD;
- }
+ lock_kernel();
+ ret = set_esp_config(info, argp);
+ unlock_kernel();
+ return ret;
+ default:
+ return -ENOIOCTLCMD;
+ }
return 0;
}
static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
change_speed(info);
@@ -1905,32 +1893,33 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/*
* ------------------------------------------------------------
* rs_close()
- *
+ *
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
* async structure from the interrupt chain if necessary, and we free
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
-static void rs_close(struct tty_struct *tty, struct file * filp)
+static void rs_close(struct tty_struct *tty, struct file *filp)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
-
+
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
goto out;
}
-
+
#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+ printk(KERN_DEBUG "rs_close ttys%d, count = %d\n",
+ info->line, info->count);
#endif
- if ((tty->count == 1) && (info->count != 1)) {
+ 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
@@ -1938,12 +1927,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk("rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
+ printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
- printk("rs_close: bad serial port count for ttys%d: %d\n",
+ printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
info->line, info->count);
info->count = 0;
}
@@ -1955,7 +1943,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
spin_unlock_irqrestore(&info->lock, flags);
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
@@ -1990,16 +1978,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
rs_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
info->tty = NULL;
if (info->blocked_open) {
- if (info->close_delay) {
+ 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);
@@ -2012,7 +1998,7 @@ out:
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
unsigned long flags;
@@ -2036,10 +2022,10 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
- break;
+ return;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
+ return;
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
@@ -2054,11 +2040,11 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
*/
static void esp_hangup(struct tty_struct *tty)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
-
+ struct esp_struct *info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "esp_hangup"))
return;
-
+
rs_flush_buffer(tty);
shutdown(info);
info->count = 0;
@@ -2072,7 +2058,7 @@ static void esp_hangup(struct tty_struct *tty)
* esp_open() and friends
* ------------------------------------------------------------
*/
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct esp_struct *info)
{
DECLARE_WAITQUEUE(wait, current);
@@ -2121,11 +2107,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n",
info->line, info->count);
#endif
spin_lock_irqsave(&info->lock, flags);
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp))
info->count--;
info->blocked_open++;
while (1) {
@@ -2147,7 +2133,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if (info->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
@@ -2166,7 +2152,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
break;
}
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
spin_unlock_irqrestore(&info->lock, flags);
@@ -2180,14 +2166,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
info->blocked_open--;
spin_unlock_irqrestore(&info->lock, flags);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
if (retval)
return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
-}
+}
/*
* This routine is called whenever a serial port is opened. It
@@ -2195,7 +2181,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
-static int esp_open(struct tty_struct *tty, struct file * filp)
+static int esp_open(struct tty_struct *tty, struct file *filp)
{
struct esp_struct *info;
int retval, line;
@@ -2218,7 +2204,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
}
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open %s, count = %d\n", tty->name, info->count);
+ printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->count);
#endif
spin_lock_irqsave(&info->lock, flags);
info->count++;
@@ -2226,7 +2212,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
info->tty = tty;
spin_unlock_irqrestore(&info->lock, flags);
-
+
/*
* Start up serial port
*/
@@ -2237,14 +2223,13 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open returning after block_til_ready with %d\n",
+ printk(KERN_DEBUG "esp_open returning after block_til_ready with %d\n",
retval);
#endif
return retval;
}
-
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open %s successful...", tty->name);
+ printk(KERN_DEBUG "esp_open %s successful...", tty->name);
#endif
return 0;
}
@@ -2262,10 +2247,10 @@ static int esp_open(struct tty_struct *tty, struct file * filp)
* number, and identifies which options were configured into this
* driver.
*/
-
-static inline void show_serial_version(void)
+
+static void show_serial_version(void)
{
- printk(KERN_INFO "%s version %s (DMA %u)\n",
+ printk(KERN_INFO "%s version %s (DMA %u)\n",
serial_name, serial_version, dma);
}
@@ -2273,7 +2258,7 @@ static inline void show_serial_version(void)
* This routine is called by espserial_init() to initialize a specific serial
* port.
*/
-static inline int autoconfig(struct esp_struct * info)
+static int autoconfig(struct esp_struct *info)
{
int port_detected = 0;
unsigned long flags;
@@ -2349,14 +2334,14 @@ static const struct tty_operations esp_ops = {
static int __init espserial_init(void)
{
int i, offset;
- struct esp_struct * info;
+ struct esp_struct *info;
struct esp_struct *last_primary = NULL;
- int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
+ int esp[] = { 0x100, 0x140, 0x180, 0x200, 0x240, 0x280, 0x300, 0x380 };
esp_driver = alloc_tty_driver(NR_PORTS);
if (!esp_driver)
return -ENOMEM;
-
+
for (i = 0; i < NR_PRIMARY; i++) {
if (irq[i] != 0) {
if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
@@ -2378,20 +2363,20 @@ static int __init espserial_init(void)
if ((flow_off < 1) || (flow_off > 1023))
flow_off = 1016;
-
+
if ((flow_on < 1) || (flow_on > 1023))
flow_on = 944;
if ((rx_timeout < 0) || (rx_timeout > 255))
rx_timeout = 128;
-
+
if (flow_on >= flow_off)
flow_on = flow_off - 1;
show_serial_version();
/* Initialize the tty_driver structure */
-
+
esp_driver->owner = THIS_MODULE;
esp_driver->name = "ttyP";
esp_driver->major = ESP_IN_MAJOR;
@@ -2401,10 +2386,11 @@ static int __init espserial_init(void)
esp_driver->init_termios = tty_std_termios;
esp_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ esp_driver->init_termios.c_ispeed = 9600;
+ esp_driver->init_termios.c_ospeed = 9600;
esp_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(esp_driver, &esp_ops);
- if (tty_register_driver(esp_driver))
- {
+ if (tty_register_driver(esp_driver)) {
printk(KERN_ERR "Couldn't register esp serial driver");
put_tty_driver(esp_driver);
return 1;
@@ -2412,8 +2398,7 @@ static int __init espserial_init(void)
info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
- if (!info)
- {
+ if (!info) {
printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
tty_unregister_driver(esp_driver);
put_tty_driver(esp_driver);
@@ -2476,10 +2461,8 @@ static int __init espserial_init(void)
info->stat_flags |= ESP_STAT_NEVER_DMA;
info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
- if (!info)
- {
- printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
-
+ if (!info) {
+ printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
/* allow use of the already detected ports */
return 0;
}
@@ -2503,22 +2486,20 @@ static int __init espserial_init(void)
return 0;
}
-static void __exit espserial_exit(void)
+static void __exit espserial_exit(void)
{
int e1;
struct esp_struct *temp_async;
struct esp_pio_buffer *pio_buf;
- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- if ((e1 = tty_unregister_driver(esp_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
- e1);
+ e1 = tty_unregister_driver(esp_driver);
+ if (e1)
+ printk(KERN_ERR "esp: failed to unregister driver (%d)\n", e1);
put_tty_driver(esp_driver);
while (ports) {
- if (ports->port) {
+ if (ports->port)
release_region(ports->port, REGION_SIZE);
- }
temp_async = ports->next_port;
kfree(ports);
ports = temp_async;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 7ed7da1d99cf..252f73e48596 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -40,27 +40,27 @@ static int gs_debug;
#define gs_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
-#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__)
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __func__)
+#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __func__)
#define RS_EVENT_WRITE_WAKEUP 1
module_param(gs_debug, int, 0644);
-void gs_put_char(struct tty_struct * tty, unsigned char ch)
+int gs_put_char(struct tty_struct * tty, unsigned char ch)
{
struct gs_port *port;
func_enter ();
- if (!tty) return;
+ if (!tty) return 0;
port = tty->driver_data;
- if (!port) return;
+ if (!port) return 0;
- if (! (port->flags & ASYNC_INITIALIZED)) return;
+ if (! (port->flags & ASYNC_INITIALIZED)) return 0;
/* Take a lock on the serial tranmit buffer! */
mutex_lock(& port->port_write_mutex);
@@ -68,7 +68,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
/* Sorry, buffer is full, drop character. Update statistics???? -- REW */
mutex_unlock(&port->port_write_mutex);
- return;
+ return 0;
}
port->xmit_buf[port->xmit_head++] = ch;
@@ -77,6 +77,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
mutex_unlock(&port->port_write_mutex);
func_exit ();
+ return 1;
}
@@ -586,8 +587,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
port->flags &= ~GS_ACTIVE;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ gs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 1399971be689..e7fb0bca3667 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -308,7 +308,7 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
- __FUNCTION__);
+ __func__);
return -EAGAIN;
}
@@ -748,7 +748,7 @@ int hpet_alloc(struct hpet_data *hdp)
*/
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: duplicate HPET ignored\n",
- __FUNCTION__);
+ __func__);
return 0;
}
@@ -869,7 +869,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __FUNCTION__, hdp->hd_phys_address);
+ __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -886,7 +886,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __FUNCTION__, hdp->hd_phys_address);
+ __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -925,7 +925,7 @@ static int hpet_acpi_add(struct acpi_device *device)
return -ENODEV;
if (!data.hd_address || !data.hd_nirqs) {
- printk("%s: no address or irqs in _CRS\n", __FUNCTION__);
+ printk("%s: no address or irqs in _CRS\n", __func__);
return -ENODEV;
}
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index d5a752da322f..59c6f9ab94e4 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -246,7 +246,7 @@ static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to)
{
int remaining = (int)(hp->inbuf_end - read_to);
- pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining);
+ pr_debug("%s: %i chars remain\n", __func__, remaining);
if (read_to != hp->inbuf)
memmove(hp->inbuf, read_to, remaining);
@@ -365,7 +365,7 @@ static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno)
packet.u.version = HVSI_VERSION;
packet.query_seqno = query_seqno+1;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -437,7 +437,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
return NULL;
if (overflow > 0) {
- pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__);
+ pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE;
}
@@ -448,7 +448,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
* we still have more data to deliver, so we need to save off the
* overflow and send it later
*/
- pr_debug("%s: deferring overflow\n", __FUNCTION__);
+ pr_debug("%s: deferring overflow\n", __func__);
memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow);
hp->n_throttle = overflow;
}
@@ -474,11 +474,11 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
if (chunklen == 0) {
- pr_debug("%s: 0-length read\n", __FUNCTION__);
+ pr_debug("%s: 0-length read\n", __func__);
return 0;
}
- pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen);
+ pr_debug("%s: got %i bytes\n", __func__, chunklen);
dbg_dump_hex(hp->inbuf_end, chunklen);
hp->inbuf_end += chunklen;
@@ -495,7 +495,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
continue;
}
- pr_debug("%s: handling %i-byte packet\n", __FUNCTION__,
+ pr_debug("%s: handling %i-byte packet\n", __func__,
len_packet(packet));
dbg_dump_packet(packet);
@@ -526,7 +526,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
packet += len_packet(packet);
if (*hangup || *handshake) {
- pr_debug("%s: hangup or handshake\n", __FUNCTION__);
+ pr_debug("%s: hangup or handshake\n", __func__);
/*
* we need to send the hangup now before receiving any more data.
* If we get "data, hangup, data", we can't deliver the second
@@ -543,7 +543,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
static void hvsi_send_overflow(struct hvsi_struct *hp)
{
- pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__,
+ pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle);
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
@@ -563,7 +563,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
unsigned long flags;
int again = 1;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
while (again) {
spin_lock_irqsave(&hp->lock, flags);
@@ -647,7 +647,7 @@ static int hvsi_query(struct hvsi_struct *hp, uint16_t verb)
packet.seqno = atomic_inc_return(&hp->seqno);
packet.verb = verb;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -674,7 +674,7 @@ static int hvsi_get_mctrl(struct hvsi_struct *hp)
return ret;
}
- pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl);
+ pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl);
return 0;
}
@@ -694,7 +694,7 @@ static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl)
if (mctrl & TIOCM_DTR)
packet.word = HVSI_TSDTR;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -790,7 +790,7 @@ static void hvsi_close_protocol(struct hvsi_struct *hp)
packet.len = 6;
packet.verb = VSV_CLOSE_PROTOCOL;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -803,7 +803,7 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
int line = tty->index;
int ret;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
if (line < 0 || line >= hvsi_count)
return -ENODEV;
@@ -868,7 +868,7 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
if (tty_hung_up_p(filp))
return;
@@ -920,7 +920,7 @@ static void hvsi_hangup(struct tty_struct *tty)
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
@@ -942,7 +942,7 @@ static void hvsi_push(struct hvsi_struct *hp)
n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf);
if (n > 0) {
/* success */
- pr_debug("%s: wrote %i chars\n", __FUNCTION__, n);
+ pr_debug("%s: wrote %i chars\n", __func__, n);
hp->n_outbuf = 0;
} else if (n == -EIO) {
__set_state(hp, HVSI_FSP_DIED);
@@ -965,7 +965,7 @@ static void hvsi_write_worker(struct work_struct *work)
spin_lock_irqsave(&hp->lock, flags);
- pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf);
+ pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
if (!is_open(hp)) {
/*
@@ -983,7 +983,7 @@ static void hvsi_write_worker(struct work_struct *work)
schedule_delayed_work(&hp->writer, 10);
else {
#ifdef DEBUG
- pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__,
+ pr_debug("%s: outbuf emptied after %li jiffies\n", __func__,
jiffies - start_j);
start_j = 0;
#endif /* DEBUG */
@@ -1020,11 +1020,11 @@ static int hvsi_write(struct tty_struct *tty,
spin_lock_irqsave(&hp->lock, flags);
- pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf);
+ pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
if (!is_open(hp)) {
/* we're either closing or not yet open; don't accept data */
- pr_debug("%s: not open\n", __FUNCTION__);
+ pr_debug("%s: not open\n", __func__);
goto out;
}
@@ -1058,7 +1058,7 @@ out:
spin_unlock_irqrestore(&hp->lock, flags);
if (total != origcount)
- pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount,
+ pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount,
total);
return total;
@@ -1072,7 +1072,7 @@ static void hvsi_throttle(struct tty_struct *tty)
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE);
}
@@ -1083,7 +1083,7 @@ static void hvsi_unthrottle(struct tty_struct *tty)
unsigned long flags;
int shouldflip = 0;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) {
@@ -1302,7 +1302,7 @@ static int __init hvsi_console_init(void)
hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
- __FUNCTION__, irq[0]);
+ __func__, irq[0]);
continue;
}
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 8609b8236c67..b60d425ce8d1 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -77,11 +77,16 @@ static int power_status;
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
+static int fan_mult = I8K_FAN_MULT;
+module_param(fan_mult, int, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+
static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static const struct file_operations i8k_fops = {
+ .owner = THIS_MODULE,
.open = i8k_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -238,7 +243,7 @@ static int i8k_get_fan_speed(int fan)
struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
regs.ebx = fan & 0xff;
- return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return i8k_smm(&regs) ? : (regs.eax & 0xffff) * fan_mult;
}
/*
@@ -554,13 +559,10 @@ static int __init i8k_init(void)
return -ENODEV;
/* Register the proc entry */
- proc_i8k = create_proc_entry("i8k", 0, NULL);
+ proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops);
if (!proc_i8k)
return -ENOENT;
- proc_i8k->proc_fops = &i8k_fops;
- proc_i8k->owner = THIS_MODULE;
-
printk(KERN_INFO
"Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
I8K_VERSION);
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index 61ef013b8445..3601017f58cf 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -53,7 +53,7 @@ static int ii2Safe; // Safe I/O address for delay routine
static int iiDelayed; // Set when the iiResetDelay function is
// called. Cleared when ANY board is reset.
-static rwlock_t Dl_spinlock;
+static DEFINE_RWLOCK(Dl_spinlock);
//********
//* Code *
@@ -82,7 +82,6 @@ static rwlock_t Dl_spinlock;
static void
iiEllisInit(void)
{
- LOCK_INIT(&Dl_spinlock);
}
//******************************************************************************
@@ -132,7 +131,7 @@ iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay )
|| (address & 0x7)
)
{
- COMPLETE(pB,I2EE_BADADDR);
+ I2_COMPLETE(pB, I2EE_BADADDR);
}
// Initialize accelerators
@@ -152,7 +151,7 @@ iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay )
pB->i2eValid = I2E_MAGIC;
pB->i2eState = II_STATE_COLD;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -177,12 +176,12 @@ iiReset(i2eBordStrPtr pB)
// Magic number should be set, else even the address is suspect
if (pB->i2eValid != I2E_MAGIC)
{
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
- OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do
+ outb(0, pB->i2eBase + FIFO_RESET); /* Any data will do */
iiDelay(pB, 50); // Pause between resets
- OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset
+ outb(0, pB->i2eBase + FIFO_RESET); /* Second reset */
// We must wait before even attempting to read anything from the FIFO: the
// board's P.O.S.T may actually attempt to read and write its end of the
@@ -203,7 +202,7 @@ iiReset(i2eBordStrPtr pB)
// Ensure anything which would have been of use to standard loadware is
// blanked out, since board has now forgotten everything!.
- pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet
+ pB->i2eUsingIrq = I2_IRQ_UNDEFINED; /* to not use an interrupt so far */
pB->i2eWaitingForEmptyFifo = 0;
pB->i2eOutMailWaiting = 0;
pB->i2eChannelPtr = NULL;
@@ -215,7 +214,7 @@ iiReset(i2eBordStrPtr pB)
pB->i2eFatalTrap = NULL;
pB->i2eFatal = 0;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -235,14 +234,14 @@ static int
iiResetDelay(i2eBordStrPtr pB)
{
if (pB->i2eValid != I2E_MAGIC) {
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_RESET) {
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
iiDelay(pB,2000); /* Now we wait for two seconds. */
iiDelayed = 1; /* Delay has been called: ok to initialize */
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -273,12 +272,12 @@ iiInitialize(i2eBordStrPtr pB)
if (pB->i2eValid != I2E_MAGIC)
{
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_RESET || !iiDelayed)
{
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
// In case there is a failure short of our completely reading the power-up
@@ -291,13 +290,12 @@ iiInitialize(i2eBordStrPtr pB)
for (itemp = 0; itemp < sizeof(porStr); itemp++)
{
// We expect the entire message is ready.
- if (HAS_NO_INPUT(pB))
- {
+ if (!I2_HAS_INPUT(pB)) {
pB->i2ePomSize = itemp;
- COMPLETE(pB, I2EE_PORM_SHORT);
+ I2_COMPLETE(pB, I2EE_PORM_SHORT);
}
- pB->i2ePom.c[itemp] = c = BYTE_FROM(pB);
+ pB->i2ePom.c[itemp] = c = inb(pB->i2eData);
// We check the magic numbers as soon as they are supposed to be read
// (rather than after) to minimize effect of reading something we
@@ -306,22 +304,22 @@ iiInitialize(i2eBordStrPtr pB)
(itemp == POR_2_INDEX && c != POR_MAGIC_2))
{
pB->i2ePomSize = itemp+1;
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
}
pB->i2ePomSize = itemp;
// Ensure that this was all the data...
- if (HAS_INPUT(pB))
- COMPLETE(pB, I2EE_PORM_LONG);
+ if (I2_HAS_INPUT(pB))
+ I2_COMPLETE(pB, I2EE_PORM_LONG);
// For now, we'll fail to initialize if P.O.S.T reports bad chip mapper:
// Implying we will not be able to download any code either: That's ok: the
// condition is pretty explicit.
if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER)
{
- COMPLETE(pB, I2EE_POSTERR);
+ I2_COMPLETE(pB, I2EE_POSTERR);
}
// Determine anything which must be done differently depending on the family
@@ -332,7 +330,7 @@ iiInitialize(i2eBordStrPtr pB)
pB->i2eFifoStyle = FIFO_II;
pB->i2eFifoSize = 512; // 512 bytes, always
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit
// slot, we do allow it to be done (documentation!)
@@ -354,7 +352,7 @@ iiInitialize(i2eBordStrPtr pB)
// should always be consistent for IntelliPort-II. Ditto below...
if (pB->i2ePom.e.porPorts1 != 4)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
@@ -364,7 +362,7 @@ iiInitialize(i2eBordStrPtr pB)
pB->i2eChannelMap[0] = 0xff; // Eight port
if (pB->i2ePom.e.porPorts1 != 8)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
@@ -373,7 +371,7 @@ iiInitialize(i2eBordStrPtr pB)
pB->i2eChannelMap[0] = 0x3f; // Six Port
if (pB->i2ePom.e.porPorts1 != 6)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
}
@@ -402,7 +400,7 @@ iiInitialize(i2eBordStrPtr pB)
if (itemp < 8 || itemp > 15)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
pB->i2eFifoSize = (1 << itemp);
@@ -450,26 +448,26 @@ iiInitialize(i2eBordStrPtr pB)
switch (pB->i2ePom.e.porBus & (POR_BUS_SLOT16 | POR_BUS_DIP16) )
{
case POR_BUS_SLOT16 | POR_BUS_DIP16:
- pB->i2eDataWidth16 = YES;
+ pB->i2eDataWidth16 = true;
pB->i2eMaxIrq = 15;
break;
case POR_BUS_SLOT16:
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 15;
break;
case 0:
case POR_BUS_DIP16: // In an 8-bit slot, DIP switch don't care.
default:
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 7;
break;
}
break; // POR_ID_FIIEX case
default: // Unknown type of board
- COMPLETE(pB, I2EE_BAD_FAMILY);
+ I2_COMPLETE(pB, I2EE_BAD_FAMILY);
break;
} // End the switch based on family
@@ -483,17 +481,14 @@ iiInitialize(i2eBordStrPtr pB)
{
case POR_BUS_T_ISA:
case POR_BUS_T_UNK: // If the type of bus is undeclared, assume ok.
- pB->i2eChangeIrq = YES;
- break;
case POR_BUS_T_MCA:
case POR_BUS_T_EISA:
- pB->i2eChangeIrq = NO;
break;
default:
- COMPLETE(pB, I2EE_BADBUS);
+ I2_COMPLETE(pB, I2EE_BADBUS);
}
- if (pB->i2eDataWidth16 == YES)
+ if (pB->i2eDataWidth16)
{
pB->i2eWriteBuf = iiWriteBuf16;
pB->i2eReadBuf = iiReadBuf16;
@@ -529,7 +524,7 @@ iiInitialize(i2eBordStrPtr pB)
break;
default:
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
// Initialize state information.
@@ -549,7 +544,7 @@ iiInitialize(i2eBordStrPtr pB)
// Everything is ok now, return with good status/
pB->i2eValid = I2E_MAGIC;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -658,7 +653,7 @@ ii2DelayIO(unsigned int mseconds)
while(mseconds--) {
int i = ii2DelValue;
while ( i-- ) {
- INB ( ii2Safe );
+ inb(ii2Safe);
}
}
}
@@ -709,11 +704,11 @@ iiWriteBuf16(i2eBordStrPtr pB, unsigned char *address, int count)
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- OUTSW ( pB->i2eData, address, count);
+ I2_OUTSW(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -738,11 +733,11 @@ iiWriteBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
{
/* Rudimentary sanity checking here */
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- OUTSB ( pB->i2eData, address, count );
+ I2_OUTSB(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -767,11 +762,11 @@ iiReadBuf16(i2eBordStrPtr pB, unsigned char *address, int count)
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- INSW ( pB->i2eData, address, count);
+ I2_INSW(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -796,11 +791,11 @@ iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- INSB ( pB->i2eData, address, count);
+ I2_INSB(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -820,7 +815,7 @@ iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count)
static unsigned short
iiReadWord16(i2eBordStrPtr pB)
{
- return (unsigned short)( INW(pB->i2eData) );
+ return inw(pB->i2eData);
}
//******************************************************************************
@@ -842,9 +837,9 @@ iiReadWord8(i2eBordStrPtr pB)
{
unsigned short urs;
- urs = INB ( pB->i2eData );
+ urs = inb(pB->i2eData);
- return ( ( INB ( pB->i2eData ) << 8 ) | urs );
+ return (inb(pB->i2eData) << 8) | urs;
}
//******************************************************************************
@@ -865,7 +860,7 @@ iiReadWord8(i2eBordStrPtr pB)
static void
iiWriteWord16(i2eBordStrPtr pB, unsigned short value)
{
- WORD_TO(pB, (int)value);
+ outw((int)value, pB->i2eData);
}
//******************************************************************************
@@ -886,8 +881,8 @@ iiWriteWord16(i2eBordStrPtr pB, unsigned short value)
static void
iiWriteWord8(i2eBordStrPtr pB, unsigned short value)
{
- BYTE_TO(pB, (char)value);
- BYTE_TO(pB, (char)(value >> 8) );
+ outb((char)value, pB->i2eData);
+ outb((char)(value >> 8), pB->i2eData);
}
//******************************************************************************
@@ -939,30 +934,30 @@ iiWaitForTxEmptyII(i2eBordStrPtr pB, int mSdelay)
// interrupts of any kind.
- WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
- OUTB(pB->i2ePointer, SEL_COMMAND);
- OUTB(pB->i2ePointer, SEL_CMD_SH);
+ write_lock_irqsave(&Dl_spinlock, flags);
+ outb(SEL_COMMAND, pB->i2ePointer);
+ outb(SEL_CMD_SH, pB->i2ePointer);
- itemp = INB(pB->i2eStatus);
+ itemp = inb(pB->i2eStatus);
- OUTB(pB->i2ePointer, SEL_COMMAND);
- OUTB(pB->i2ePointer, SEL_CMD_UNSH);
+ outb(SEL_COMMAND, pB->i2ePointer);
+ outb(SEL_CMD_UNSH, pB->i2ePointer);
if (itemp & ST_IN_EMPTY)
{
- UPDATE_FIFO_ROOM(pB);
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
- COMPLETE(pB, I2EE_GOOD);
+ I2_UPDATE_FIFO_ROOM(pB);
+ write_unlock_irqrestore(&Dl_spinlock, flags);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ write_unlock_irqrestore(&Dl_spinlock, flags);
if (mSdelay-- == 0)
break;
iiDelay(pB, 1); /* 1 mS granularity on checking condition */
}
- COMPLETE(pB, I2EE_TXE_TIME);
+ I2_COMPLETE(pB, I2EE_TXE_TIME);
}
//******************************************************************************
@@ -1002,21 +997,21 @@ iiWaitForTxEmptyIIEX(i2eBordStrPtr pB, int mSdelay)
// you will generally not want to service interrupts or in any way
// disrupt the assumptions implicit in the larger context.
- WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
+ write_lock_irqsave(&Dl_spinlock, flags);
- if (INB(pB->i2eStatus) & STE_OUT_MT) {
- UPDATE_FIFO_ROOM(pB);
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
- COMPLETE(pB, I2EE_GOOD);
+ if (inb(pB->i2eStatus) & STE_OUT_MT) {
+ I2_UPDATE_FIFO_ROOM(pB);
+ write_unlock_irqrestore(&Dl_spinlock, flags);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ write_unlock_irqrestore(&Dl_spinlock, flags);
if (mSdelay-- == 0)
break;
iiDelay(pB, 1); // 1 mS granularity on checking condition
}
- COMPLETE(pB, I2EE_TXE_TIME);
+ I2_COMPLETE(pB, I2EE_TXE_TIME);
}
//******************************************************************************
@@ -1038,8 +1033,8 @@ static int
iiTxMailEmptyII(i2eBordStrPtr pB)
{
int port = pB->i2ePointer;
- OUTB ( port, SEL_OUTMAIL );
- return ( INB(port) == 0 );
+ outb(SEL_OUTMAIL, port);
+ return inb(port) == 0;
}
//******************************************************************************
@@ -1060,7 +1055,7 @@ iiTxMailEmptyII(i2eBordStrPtr pB)
static int
iiTxMailEmptyIIEX(i2eBordStrPtr pB)
{
- return !(INB(pB->i2eStatus) & STE_OUT_MAIL);
+ return !(inb(pB->i2eStatus) & STE_OUT_MAIL);
}
//******************************************************************************
@@ -1084,10 +1079,10 @@ iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail)
{
int port = pB->i2ePointer;
- OUTB(port, SEL_OUTMAIL);
- if (INB(port) == 0) {
- OUTB(port, SEL_OUTMAIL);
- OUTB(port, mail);
+ outb(SEL_OUTMAIL, port);
+ if (inb(port) == 0) {
+ outb(SEL_OUTMAIL, port);
+ outb(mail, port);
return 1;
}
return 0;
@@ -1112,10 +1107,9 @@ iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail)
static int
iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail)
{
- if(INB(pB->i2eStatus) & STE_OUT_MAIL) {
+ if (inb(pB->i2eStatus) & STE_OUT_MAIL)
return 0;
- }
- OUTB(pB->i2eXMail, mail);
+ outb(mail, pB->i2eXMail);
return 1;
}
@@ -1136,9 +1130,9 @@ iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail)
static unsigned short
iiGetMailII(i2eBordStrPtr pB)
{
- if (HAS_MAIL(pB)) {
- OUTB(pB->i2ePointer, SEL_INMAIL);
- return INB(pB->i2ePointer);
+ if (I2_HAS_MAIL(pB)) {
+ outb(SEL_INMAIL, pB->i2ePointer);
+ return inb(pB->i2ePointer);
} else {
return NO_MAIL_HERE;
}
@@ -1161,11 +1155,10 @@ iiGetMailII(i2eBordStrPtr pB)
static unsigned short
iiGetMailIIEX(i2eBordStrPtr pB)
{
- if (HAS_MAIL(pB)) {
- return INB(pB->i2eXMail);
- } else {
+ if (I2_HAS_MAIL(pB))
+ return inb(pB->i2eXMail);
+ else
return NO_MAIL_HERE;
- }
}
//******************************************************************************
@@ -1184,8 +1177,8 @@ iiGetMailIIEX(i2eBordStrPtr pB)
static void
iiEnableMailIrqII(i2eBordStrPtr pB)
{
- OUTB(pB->i2ePointer, SEL_MASK);
- OUTB(pB->i2ePointer, ST_IN_MAIL);
+ outb(SEL_MASK, pB->i2ePointer);
+ outb(ST_IN_MAIL, pB->i2ePointer);
}
//******************************************************************************
@@ -1204,7 +1197,7 @@ iiEnableMailIrqII(i2eBordStrPtr pB)
static void
iiEnableMailIrqIIEX(i2eBordStrPtr pB)
{
- OUTB(pB->i2eXMask, MX_IN_MAIL);
+ outb(MX_IN_MAIL, pB->i2eXMask);
}
//******************************************************************************
@@ -1223,8 +1216,8 @@ iiEnableMailIrqIIEX(i2eBordStrPtr pB)
static void
iiWriteMaskII(i2eBordStrPtr pB, unsigned char value)
{
- OUTB(pB->i2ePointer, SEL_MASK);
- OUTB(pB->i2ePointer, value);
+ outb(SEL_MASK, pB->i2ePointer);
+ outb(value, pB->i2ePointer);
}
//******************************************************************************
@@ -1243,7 +1236,7 @@ iiWriteMaskII(i2eBordStrPtr pB, unsigned char value)
static void
iiWriteMaskIIEX(i2eBordStrPtr pB, unsigned char value)
{
- OUTB(pB->i2eXMask, value);
+ outb(value, pB->i2eXMask);
}
//******************************************************************************
@@ -1354,9 +1347,8 @@ iiDownloadBlock ( i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard)
// immediately and be harmless, though not strictly necessary.
itemp = MAX_DLOAD_ACK_TIME/10;
while (--itemp) {
- if (HAS_INPUT(pB)) {
- switch(BYTE_FROM(pB))
- {
+ if (I2_HAS_INPUT(pB)) {
+ switch (inb(pB->i2eData)) {
case LOADWARE_OK:
pB->i2eState =
isStandard ? II_STATE_STDLOADED :II_STATE_LOADED;
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index 433305062fb8..c88a64e527aa 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -185,10 +185,6 @@ typedef struct _i2eBordStr
// The highest allowable IRQ, based on the
// slot size.
- unsigned char i2eChangeIrq;
- // Whether tis valid to change IRQ's
- // ISA = ok, EISA, MicroChannel, no
-
// Accelerators for various addresses on the board
int i2eBase; // I/O Address of the Board
int i2eData; // From here data transfers happen
@@ -431,12 +427,6 @@ typedef struct _i2eBordStr
// Manifests for i2eBordStr:
//-------------------------------------------
-#define YES 1
-#define NO 0
-
-#define NULLFUNC (void (*)(void))0
-#define NULLPTR (void *)0
-
typedef void (*delayFunc_t)(unsigned int);
// i2eValid
@@ -494,8 +484,8 @@ typedef void (*delayFunc_t)(unsigned int);
// i2eUsingIrq
//
-#define IRQ_UNDEFINED 0x1352 // No valid irq (or polling = 0) can ever
- // promote to this!
+#define I2_IRQ_UNDEFINED 0x1352 /* No valid irq (or polling = 0) can
+ * ever promote to this! */
//------------------------------------------
// Handy Macros for i2ellis.c and others
// Note these are common to -II and -IIEX
@@ -504,41 +494,14 @@ typedef void (*delayFunc_t)(unsigned int);
// Given a pointer to the board structure, does the input FIFO have any data or
// not?
//
-#define HAS_INPUT(pB) !(INB(pB->i2eStatus) & ST_IN_EMPTY)
-#define HAS_NO_INPUT(pB) (INB(pB->i2eStatus) & ST_IN_EMPTY)
-
-// Given a pointer to board structure, read a byte or word from the fifo
-//
-#define BYTE_FROM(pB) (unsigned char)INB(pB->i2eData)
-#define WORD_FROM(pB) (unsigned short)INW(pB->i2eData)
-
-// Given a pointer to board structure, is there room for any data to be written
-// to the data fifo?
-//
-#define HAS_OUTROOM(pB) !(INB(pB->i2eStatus) & ST_OUT_FULL)
-#define HAS_NO_OUTROOM(pB) (INB(pB->i2eStatus) & ST_OUT_FULL)
-
-// Given a pointer to board structure, write a single byte to the fifo
-// structure. Note that for 16-bit interfaces, the high order byte is undefined
-// and unknown.
-//
-#define BYTE_TO(pB, c) OUTB(pB->i2eData,(c))
-
-// Write a word to the fifo structure. For 8-bit interfaces, this may have
-// unknown results.
-//
-#define WORD_TO(pB, c) OUTW(pB->i2eData,(c))
+#define I2_HAS_INPUT(pB) !(inb(pB->i2eStatus) & ST_IN_EMPTY)
// Given a pointer to the board structure, is there anything in the incoming
// mailbox?
//
-#define HAS_MAIL(pB) (INB(pB->i2eStatus) & ST_IN_MAIL)
+#define I2_HAS_MAIL(pB) (inb(pB->i2eStatus) & ST_IN_MAIL)
-#define UPDATE_FIFO_ROOM(pB) (pB)->i2eFifoRemains=(pB)->i2eFifoSize
-
-// Handy macro to round up a number (like the buffer write and read routines do)
-//
-#define ROUNDUP(number) (((number)+1) & (~1))
+#define I2_UPDATE_FIFO_ROOM(pB) ((pB)->i2eFifoRemains = (pB)->i2eFifoSize)
//------------------------------------------
// Function Declarations for i2ellis.c
@@ -593,20 +556,11 @@ static int iiDownloadBlock(i2eBordStrPtr, loadHdrStrPtr, int);
//
static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int);
-// Called indirectly always. Needed externally so the routine might be
-// SPECIFIED as an argument to iiReset()
-//
-//static void ii2DelayIO(unsigned int); // N-millisecond delay using
- //hardware spin
-//static void ii2DelayTimer(unsigned int); // N-millisecond delay using Linux
- //timer
-
// Many functions defined here return True if good, False otherwise, with an
// error code in i2eError field. Here is a handy macro for setting the error
// code and returning.
//
-#define COMPLETE(pB,code) \
- do { \
+#define I2_COMPLETE(pB,code) do { \
pB->i2eError = code; \
return (code == I2EE_GOOD);\
} while (0)
diff --git a/drivers/char/ip2/i2hw.h b/drivers/char/ip2/i2hw.h
index 15fe04e748f4..8aa6e7ab8d5b 100644
--- a/drivers/char/ip2/i2hw.h
+++ b/drivers/char/ip2/i2hw.h
@@ -129,7 +129,6 @@ registers, use byte operations only.
//------------------------------------------------
//
#include "ip2types.h"
-#include "i2os.h" /* For any o.s., compiler, or host-related issues */
//-------------------------------------------------------------------------
// Manifests for the I/O map:
@@ -644,5 +643,10 @@ typedef union _loadHdrStr
#define ABS_BIGGEST_BOX 16 // Absolute the most ports per box
#define ABS_MOST_PORTS (ABS_MAX_BOXES * ABS_BIGGEST_BOX)
+#define I2_OUTSW(port, addr, count) outsw((port), (addr), (((count)+1)/2))
+#define I2_OUTSB(port, addr, count) outsb((port), (addr), (((count)+1))&-2)
+#define I2_INSW(port, addr, count) insw((port), (addr), (((count)+1)/2))
+#define I2_INSB(port, addr, count) insb((port), (addr), (((count)+1))&-2)
+
#endif // I2HW_H
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 9c25320121ef..938879cc7bcc 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -227,17 +227,17 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
i2ChanStrPtr *ppCh;
if (pB->i2eValid != I2E_MAGIC) {
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_STDLOADED) {
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
- LOCK_INIT(&pB->read_fifo_spinlock);
- LOCK_INIT(&pB->write_fifo_spinlock);
- LOCK_INIT(&pB->Dbuf_spinlock);
- LOCK_INIT(&pB->Bbuf_spinlock);
- LOCK_INIT(&pB->Fbuf_spinlock);
+ rwlock_init(&pB->read_fifo_spinlock);
+ rwlock_init(&pB->write_fifo_spinlock);
+ rwlock_init(&pB->Dbuf_spinlock);
+ rwlock_init(&pB->Bbuf_spinlock);
+ rwlock_init(&pB->Fbuf_spinlock);
// NO LOCK needed yet - this is init
@@ -259,10 +259,10 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) {
continue;
}
- LOCK_INIT(&pCh->Ibuf_spinlock);
- LOCK_INIT(&pCh->Obuf_spinlock);
- LOCK_INIT(&pCh->Cbuf_spinlock);
- LOCK_INIT(&pCh->Pbuf_spinlock);
+ rwlock_init(&pCh->Ibuf_spinlock);
+ rwlock_init(&pCh->Obuf_spinlock);
+ rwlock_init(&pCh->Cbuf_spinlock);
+ rwlock_init(&pCh->Pbuf_spinlock);
// NO LOCK needed yet - this is init
// Set up validity flag according to support level
if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) {
@@ -347,7 +347,7 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh)
}
// No need to check for wrap here; this is initialization.
pB->i2Fbuf_stuff = stuffIndex;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
@@ -374,7 +374,7 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
case NEED_INLINE:
- WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Dbuf_spinlock, flags);
if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip)
{
queueIndex = pB->i2Dbuf_strip;
@@ -386,12 +386,12 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
pB->i2Dbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_INLINE;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Dbuf_spinlock, flags);
break;
case NEED_BYPASS:
- WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Bbuf_spinlock, flags);
if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip)
{
queueIndex = pB->i2Bbuf_strip;
@@ -403,12 +403,12 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
pB->i2Bbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_BYPASS;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Bbuf_spinlock, flags);
break;
case NEED_FLOW:
- WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Fbuf_spinlock, flags);
if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip)
{
queueIndex = pB->i2Fbuf_strip;
@@ -420,7 +420,7 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type)
pB->i2Fbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_FLOW;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Fbuf_spinlock, flags);
break;
default:
printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type);
@@ -453,7 +453,7 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
case NEED_INLINE:
- WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Dbuf_spinlock, flags);
if ( !(pCh->channelNeeds & NEED_INLINE) )
{
pCh->channelNeeds |= NEED_INLINE;
@@ -463,12 +463,12 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
queueIndex = 0;
pB->i2Dbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Dbuf_spinlock, flags);
break;
case NEED_BYPASS:
- WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Bbuf_spinlock, flags);
if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS))
{
pCh->channelNeeds |= NEED_BYPASS;
@@ -478,12 +478,12 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
queueIndex = 0;
pB->i2Bbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Bbuf_spinlock, flags);
break;
case NEED_FLOW:
- WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Fbuf_spinlock, flags);
if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW))
{
pCh->channelNeeds |= NEED_FLOW;
@@ -493,7 +493,7 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type)
queueIndex = 0;
pB->i2Fbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Fbuf_spinlock, flags);
break;
case NEED_CREDIT:
@@ -562,9 +562,8 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
pB = pCh->pMyBord;
// Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT
- if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) {
+ if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == I2_IRQ_UNDEFINED)
return -2;
- }
// If the board has gone fatal, return bad, and also hit the trap routine if
// it exists.
if (pB->i2eFatal) {
@@ -620,13 +619,13 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
switch(type) {
case PTYPE_INLINE:
lock_var_p = &pCh->Obuf_spinlock;
- WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ write_lock_irqsave(lock_var_p, flags);
stuffIndex = pCh->Obuf_stuff;
bufroom = pCh->Obuf_strip - stuffIndex;
break;
case PTYPE_BYPASS:
lock_var_p = &pCh->Cbuf_spinlock;
- WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ write_lock_irqsave(lock_var_p, flags);
stuffIndex = pCh->Cbuf_stuff;
bufroom = pCh->Cbuf_strip - stuffIndex;
break;
@@ -645,7 +644,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
break; /* from for()- Enough room: goto proceed */
}
ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize);
- WRITE_UNLOCK_IRQRESTORE(lock_var_p, flags);
+ write_unlock_irqrestore(lock_var_p, flags);
} else
ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize);
@@ -747,7 +746,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
{
case PTYPE_INLINE:
pCh->Obuf_stuff = stuffIndex; // Store buffer pointer
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
pB->debugInlineQueued++;
// Add the channel pointer to list of channels needing service (first
@@ -757,7 +756,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
case PTYPE_BYPASS:
pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer
- WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags);
pB->debugBypassQueued++;
// Add the channel pointer to list of channels needing service (first
@@ -840,7 +839,7 @@ i2Input(i2ChanStrPtr pCh)
count = -1;
goto i2Input_exit;
}
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, flags);
// initialize some accelerators and private copies
stripIndex = pCh->Ibuf_strip;
@@ -850,7 +849,7 @@ i2Input(i2ChanStrPtr pCh)
// If buffer is empty or requested data count was 0, (trivial case) return
// without any further thought.
if ( count == 0 ) {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
goto i2Input_exit;
}
// Adjust for buffer wrap
@@ -891,10 +890,10 @@ i2Input(i2ChanStrPtr pCh)
if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) {
pCh->sinceLastFlow -= pCh->whenSendFlow;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
} else {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
i2Input_exit:
@@ -926,7 +925,7 @@ i2InputFlush(i2ChanStrPtr pCh)
ip2trace (CHANN, ITRC_INPUT, 10, 0);
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, flags);
count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
// Adjust for buffer wrap
@@ -947,10 +946,10 @@ i2InputFlush(i2ChanStrPtr pCh)
if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow )
{
pCh->sinceLastFlow -= pCh->whenSendFlow;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
} else {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
ip2trace (CHANN, ITRC_INPUT, 19, 1, count);
@@ -979,9 +978,9 @@ i2InputAvailable(i2ChanStrPtr pCh)
// initialize some accelerators and private copies
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
// Adjust for buffer wrap
if (count < 0)
@@ -1045,9 +1044,9 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
while ( count > 0 ) {
// How much room in output buffer is there?
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if (amountToMove < 0) {
amountToMove += OBUF_SIZE;
}
@@ -1075,7 +1074,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) )
&& amountToMove > 0 )
{
- WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Obuf_spinlock, flags);
stuffIndex = pCh->Obuf_stuff;
// Had room to move some data: don't know whether the block size,
@@ -1102,7 +1101,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
}
pCh->Obuf_stuff = stuffIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex );
@@ -1352,9 +1351,9 @@ i2OutputFree(i2ChanStrPtr pCh)
if ( !i2Validate ( pCh ) ) {
return -1;
}
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if (amountToMove < 0) {
amountToMove += OBUF_SIZE;
@@ -1464,11 +1463,11 @@ i2StripFifo(i2eBordStrPtr pB)
// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 );
- while (HAS_INPUT(pB)) {
+ while (I2_HAS_INPUT(pB)) {
// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 );
// Process packet from fifo a one atomic unit
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, bflags);
// The first word (or two bytes) will have channel number and type of
// packet, possibly other information
@@ -1490,7 +1489,8 @@ i2StripFifo(i2eBordStrPtr pB)
// sick!
if ( ((unsigned int)count) > IBUF_SIZE ) {
pB->i2eFatal = 2;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
return; /* Bail out ASAP */
}
// Channel is illegally big ?
@@ -1498,7 +1498,8 @@ i2StripFifo(i2eBordStrPtr pB)
(NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])))
{
iiReadBuf(pB, junkBuffer, count);
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
break; /* From switch: ready for next packet */
}
@@ -1512,14 +1513,15 @@ i2StripFifo(i2eBordStrPtr pB)
if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY)
{
pCh->hotKeyIn = iiReadWord(pB) & 0xff;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK);
break; /* From the switch: ready for next packet */
}
// Normal data! We crudely assume there is room for the data in our
// buffer because the board wouldn't have exceeded his credit limit.
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, cflags);
// We have 2 locks now
stuffIndex = pCh->Ibuf_stuff;
amountToRead = IBUF_SIZE - stuffIndex;
@@ -1562,8 +1564,9 @@ i2StripFifo(i2eBordStrPtr pB)
// Update stuff index
pCh->Ibuf_stuff = stuffIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags);
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, cflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
#ifdef USE_IQ
schedule_work(&pCh->tqueue_input);
@@ -1585,7 +1588,8 @@ i2StripFifo(i2eBordStrPtr pB)
iiReadBuf(pB, cmdBuffer, count);
// We can release early with buffer grab
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
pc = cmdBuffer;
pcLimit = &(cmdBuffer[count]);
@@ -1830,12 +1834,12 @@ i2StripFifo(i2eBordStrPtr pB)
default: // Neither packet? should be impossible
ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1,
PTYPE_OF(pB->i2eLeadoffWord) );
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
bflags);
break;
} // End of switch on type of packets
- } //while(board HAS_INPUT)
+ } /*while(board I2_HAS_INPUT)*/
ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 );
@@ -1858,7 +1862,7 @@ i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve)
{
int rc = 0;
unsigned long flags;
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
if (!pB->i2eWaitingForEmptyFifo) {
if (pB->i2eFifoRemains > (count+reserve)) {
pB->i2eFifoRemains -= count;
@@ -1867,7 +1871,7 @@ i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve)
rc = count;
}
}
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
return rc;
}
//******************************************************************************
@@ -1898,7 +1902,7 @@ i2StuffFifoBypass(i2eBordStrPtr pB)
while ( --bailout && notClogged &&
(NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS))))
{
- WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Cbuf_spinlock, flags);
stripIndex = pCh->Cbuf_strip;
// as long as there are packets for this channel...
@@ -1906,7 +1910,7 @@ i2StuffFifoBypass(i2eBordStrPtr pB)
while (stripIndex != pCh->Cbuf_stuff) {
pRemove = &(pCh->Cbuf[stripIndex]);
packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader);
- paddedSize = ROUNDUP(packetSize);
+ paddedSize = roundup(packetSize, 2);
if (paddedSize > 0) {
if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) {
@@ -1930,7 +1934,7 @@ WriteDBGBuf("BYPS", pRemove, paddedSize);
// Done with this channel. Move to next, removing this one from
// the queue of channels if we cleaned it out (i.e., didn't get clogged.
pCh->Cbuf_strip = stripIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags);
} // Either clogged or finished all the work
#ifdef IP2DEBUG_TRACE
@@ -1954,7 +1958,7 @@ static inline void
i2StuffFifoFlow(i2eBordStrPtr pB)
{
i2ChanStrPtr pCh;
- unsigned short paddedSize = ROUNDUP(sizeof(flowIn));
+ unsigned short paddedSize = roundup(sizeof(flowIn), 2);
ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2,
pB->i2eFifoRemains, paddedSize );
@@ -2010,7 +2014,7 @@ i2StuffFifoInline(i2eBordStrPtr pB)
while ( --bailout && notClogged &&
(NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) )
{
- WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Obuf_spinlock, flags);
stripIndex = pCh->Obuf_strip;
ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff );
@@ -2031,7 +2035,7 @@ i2StuffFifoInline(i2eBordStrPtr pB)
packetSize = flowsize + sizeof(i2CmdHeader);
}
flowsize = CREDIT_USAGE(flowsize);
- paddedSize = ROUNDUP(packetSize);
+ paddedSize = roundup(packetSize, 2);
ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize );
@@ -2086,7 +2090,7 @@ WriteDBGBuf("DATA", pRemove, paddedSize);
// Done with this channel. Move to next, removing this one from the
// queue of channels if we cleaned it out (i.e., didn't get clogged.
pCh->Obuf_strip = stripIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if ( notClogged )
{
@@ -2190,10 +2194,11 @@ i2ServiceBoard ( i2eBordStrPtr pB )
if (inmail & MB_OUT_STRIPPED) {
pB->i2eFifoOutInts++;
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
pB->i2eFifoRemains = pB->i2eFifoSize;
pB->i2eWaitingForEmptyFifo = 0;
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock,
+ flags);
ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains );
diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h
deleted file mode 100644
index eff9b542d699..000000000000
--- a/drivers/char/ip2/i2os.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
-*
-* (c) 1999 by Computone Corporation
-*
-********************************************************************************
-*
-*
-* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
-* serial I/O controllers.
-*
-* DESCRIPTION: Defines, definitions and includes which are heavily dependent
-* on O/S, host, compiler, etc. This file is tailored for:
-* Linux v2.0.0 and later
-* Gnu gcc c2.7.2
-* 80x86 architecture
-*
-*******************************************************************************/
-
-#ifndef I2OS_H /* To prevent multiple includes */
-#define I2OS_H 1
-
-//-------------------------------------------------
-// Required Includes
-//-------------------------------------------------
-
-#include "ip2types.h"
-#include <asm/io.h> /* For inb, etc */
-
-//------------------------------------
-// Defines for I/O instructions:
-//------------------------------------
-
-#define INB(port) inb(port)
-#define OUTB(port,value) outb((value),(port))
-#define INW(port) inw(port)
-#define OUTW(port,value) outw((value),(port))
-#define OUTSW(port,addr,count) outsw((port),(addr),(((count)+1)/2))
-#define OUTSB(port,addr,count) outsb((port),(addr),(((count)+1))&-2)
-#define INSW(port,addr,count) insw((port),(addr),(((count)+1)/2))
-#define INSB(port,addr,count) insb((port),(addr),(((count)+1))&-2)
-
-//--------------------------------------------
-// Interrupt control
-//--------------------------------------------
-
-#define LOCK_INIT(a) rwlock_init(a)
-
-#define SAVE_AND_DISABLE_INTS(a,b) { \
- /* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- spin_lock_irqsave(a,b); \
-}
-
-#define RESTORE_INTS(a,b) { \
- /* printk("rel_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- spin_unlock_irqrestore(a,b); \
-}
-
-#define READ_LOCK_IRQSAVE(a,b) { \
- /* printk("get_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- read_lock_irqsave(a,b); \
-}
-
-#define READ_UNLOCK_IRQRESTORE(a,b) { \
- /* printk("rel_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- read_unlock_irqrestore(a,b); \
-}
-
-#define WRITE_LOCK_IRQSAVE(a,b) { \
- /* printk("get_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- write_lock_irqsave(a,b); \
-}
-
-#define WRITE_UNLOCK_IRQRESTORE(a,b) { \
- /* printk("rel_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- write_unlock_irqrestore(a,b); \
-}
-
-
-//------------------------------------------------------------------------------
-// Hardware-delay loop
-//
-// Probably used in only one place (see i2ellis.c) but this helps keep things
-// together. Note we have unwound the IN instructions. On machines with a
-// reasonable cache, the eight instructions (1 byte each) should fit in cache
-// nicely, and on un-cached machines, the code-fetch would tend not to dominate.
-// Note that cx is shifted so that "count" still reflects the total number of
-// iterations assuming no unwinding.
-//------------------------------------------------------------------------------
-
-//#define DELAY1MS(port,count,label)
-
-//------------------------------------------------------------------------------
-// Macros to switch to a new stack, saving stack pointers, and to restore the
-// old stack (Used, for example, in i2lib.c) "heap" is the address of some
-// buffer which will become the new stack (working down from highest address).
-// The two words at the two lowest addresses in this stack are for storing the
-// SS and SP.
-//------------------------------------------------------------------------------
-
-//#define TO_NEW_STACK(heap,size)
-//#define TO_OLD_STACK(heap)
-
-//------------------------------------------------------------------------------
-// Macros to save the original IRQ vectors and masks, and to patch in new ones.
-//------------------------------------------------------------------------------
-
-//#define SAVE_IRQ_MASKS(dest)
-//#define WRITE_IRQ_MASKS(src)
-//#define SAVE_IRQ_VECTOR(value,dest)
-//#define WRITE_IRQ_VECTOR(value,src)
-
-//------------------------------------------------------------------------------
-// Macro to copy data from one far pointer to another.
-//------------------------------------------------------------------------------
-
-#define I2_MOVE_DATA(fpSource,fpDest,count) memmove(fpDest,fpSource,count);
-
-//------------------------------------------------------------------------------
-// Macros to issue eoi's to host interrupt control (IBM AT 8259-style).
-//------------------------------------------------------------------------------
-
-//#define MASTER_EOI
-//#define SLAVE_EOI
-
-#endif /* I2OS_H */
-
-
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index b1d6cad84282..70957acaa960 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -133,8 +133,9 @@
*****************/
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
-static int ip2_read_procmem(char *, char **, off_t, int);
+static const struct file_operations ip2mem_proc_fops;
static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
/********************/
@@ -168,7 +169,7 @@ static int Fip_firmware_size;
static int ip2_open(PTTY, struct file *);
static void ip2_close(PTTY, struct file *);
static int ip2_write(PTTY, const unsigned char *, int);
-static void ip2_putchar(PTTY, unsigned char);
+static int ip2_putchar(PTTY, unsigned char);
static void ip2_flush_chars(PTTY);
static int ip2_write_room(PTTY);
static int ip2_chars_in_buf(PTTY);
@@ -354,14 +355,15 @@ have_requested_irq( char irq )
/* the driver initialisation function and returns what it returns. */
/******************************************************************************/
#ifdef MODULE
-int
-init_module(void)
+static int __init
+ip2_init_module(void)
{
#ifdef IP2DEBUG_INIT
printk (KERN_DEBUG "Loading module ...\n" );
#endif
return 0;
}
+module_init(ip2_init_module);
#endif /* MODULE */
/******************************************************************************/
@@ -380,8 +382,8 @@ init_module(void)
/* driver should be returned since it may be unloaded from memory. */
/******************************************************************************/
#ifdef MODULE
-void
-cleanup_module(void)
+void __exit
+ip2_cleanup_module(void)
{
int err;
int i;
@@ -423,7 +425,7 @@ cleanup_module(void)
}
put_tty_driver(ip2_tty_driver);
unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
- remove_proc_entry("ip2mem", &proc_root);
+ remove_proc_entry("ip2mem", NULL);
// free memory
for (i = 0; i < IP2_MAX_BOARDS; i++) {
@@ -451,6 +453,7 @@ cleanup_module(void)
printk (KERN_DEBUG "IP2 Unloaded\n" );
#endif
}
+module_exit(ip2_cleanup_module);
#endif /* MODULE */
static const struct tty_operations ip2_ops = {
@@ -695,7 +698,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
}
}
/* Register the read_procmem thing */
- if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) {
+ if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
printk(KERN_ERR "IP2: failed to register read_procmem\n");
} else {
@@ -1049,9 +1052,9 @@ set_irq( int boardnum, int boardIrq )
* Write to FIFO; don't bother to adjust fifo capacity for this, since
* board will respond almost immediately after SendMail hit.
*/
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 4);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
pB->i2eUsingIrq = boardIrq;
pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
@@ -1069,9 +1072,9 @@ set_irq( int boardnum, int boardIrq )
(CMD_OF(tempCommand))[4] = 64; // chars
(CMD_OF(tempCommand))[5] = 87; // HW_TEST
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 8);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
CHANNEL_OF(tempCommand) = 0;
PTYPE_OF(tempCommand) = PTYPE_BYPASS;
@@ -1086,9 +1089,9 @@ set_irq( int boardnum, int boardIrq )
CMD_COUNT_OF(tempCommand) = 2;
(CMD_OF(tempCommand))[0] = 44; /* get ping */
(CMD_OF(tempCommand))[1] = 200; /* 200 ms */
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 4);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
#endif
iiEnableMailIrq(pB);
@@ -1267,12 +1270,12 @@ static void do_input(struct work_struct *work)
// Data input
if ( pCh->pTTY != NULL ) {
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2Input( pCh );
} else
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
} else {
ip2trace(CHANN, ITRC_INPUT, 22, 0 );
@@ -1613,10 +1616,8 @@ ip2_close( PTTY tty, struct file *pFile )
serviceOutgoingFifo ( pCh->pMyBord );
- if ( tty->driver->flush_buffer )
- tty->driver->flush_buffer(tty);
- if ( tty->ldisc.flush_buffer )
- tty->ldisc.flush_buffer(tty);
+ tty_ldisc_flush(tty);
+ tty_driver_flush_buffer(tty);
tty->closing = 0;
pCh->pTTY = NULL;
@@ -1716,9 +1717,9 @@ ip2_write( PTTY tty, const unsigned char *pData, int count)
ip2_flush_chars( tty );
/* This is the actual move bit. Make sure it does what we need!!!!! */
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
bytesSent = i2Output( pCh, pData, count);
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
@@ -1735,7 +1736,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count)
/* */
/* */
/******************************************************************************/
-static void
+static int
ip2_putchar( PTTY tty, unsigned char ch )
{
i2ChanStrPtr pCh = tty->driver_data;
@@ -1743,13 +1744,14 @@ ip2_putchar( PTTY tty, unsigned char ch )
// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2_flush_chars( tty );
} else
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
+ return 1;
// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
}
@@ -1769,7 +1771,7 @@ ip2_flush_chars( PTTY tty )
i2ChanStrPtr pCh = tty->driver_data;
unsigned long flags;
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
if ( pCh->Pbuf_stuff ) {
// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
@@ -1783,7 +1785,7 @@ ip2_flush_chars( PTTY tty )
}
pCh->Pbuf_stuff -= strip;
}
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
}
/******************************************************************************/
@@ -1801,9 +1803,9 @@ ip2_write_room ( PTTY tty )
i2ChanStrPtr pCh = tty->driver_data;
unsigned long flags;
- READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
- READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
@@ -1833,12 +1835,12 @@ ip2_chars_in_buf ( PTTY tty )
pCh->Obuf_char_count + pCh->Pbuf_stuff,
pCh->Obuf_char_count, pCh->Pbuf_stuff );
#endif
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
rc = pCh->Obuf_char_count;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
- READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
+ read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
rc += pCh->Pbuf_stuff;
- READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
return rc;
}
@@ -1862,9 +1864,9 @@ ip2_flush_buffer( PTTY tty )
#ifdef IP2DEBUG_WRITE
printk (KERN_DEBUG "IP2: flush buffer\n" );
#endif
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
pCh->Pbuf_stuff = 0;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
i2FlushOutput( pCh );
ip2_owake(tty);
@@ -1950,15 +1952,15 @@ ip2_unthrottle ( PTTY tty )
pCh->throttled = 0;
i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
serviceOutgoingFifo( pCh->pMyBord );
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
#ifdef IP2DEBUG_READ
printk (KERN_DEBUG "i2Input called from unthrottle\n" );
#endif
i2Input( pCh );
} else
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
static void
@@ -2201,9 +2203,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
* for masking). Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cprev = pCh->icount; /* note the counters on entry */
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
init_waitqueue_entry(&wait, current);
@@ -2223,9 +2225,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
rc = -ERESTARTSYS;
break;
}
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount; /* atomic copy */
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
rc = -EIO; /* no change => rc */
@@ -2263,9 +2265,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
case TIOCGICOUNT:
ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
p_cuser = argp;
rc = put_user(cnow.cts, &p_cuser->cts);
rc = put_user(cnow.dsr, &p_cuser->dsr);
@@ -2871,7 +2873,7 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
case 65: /* Board - ip2stat */
if ( pB ) {
rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
- rc = put_user(INB(pB->i2eStatus),
+ rc = put_user(inb(pB->i2eStatus),
(ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
} else {
rc = -ENODEV;
@@ -2967,65 +2969,61 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile )
}
return 0;
}
-/******************************************************************************/
-/* Function: ip2_read_procmem */
-/* Parameters: */
-/* */
-/* Returns: Length of output */
-/* */
-/* Description: */
-/* Supplies some driver operating parameters */
-/* Not real useful unless your debugging the fifo */
-/* */
-/******************************************************************************/
-
-#define LIMIT (PAGE_SIZE - 120)
static int
-ip2_read_procmem(char *buf, char **start, off_t offset, int len)
+proc_ip2mem_show(struct seq_file *m, void *v)
{
i2eBordStrPtr pB;
i2ChanStrPtr pCh;
PTTY tty;
int i;
- len = 0;
-
#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
- len += sprintf(buf+len,"\n");
+ seq_printf(m,"\n");
for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
pB = i2BoardPtrTable[i];
if ( pB ) {
- len += sprintf(buf+len,"board %d:\n",i);
- len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n",
+ seq_printf(m,"board %d:\n",i);
+ seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
}
}
- len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n");
+ seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
for (i=0; i < IP2_MAX_PORTS; i++) {
- if (len > LIMIT)
- break;
pCh = DevTable[i];
if (pCh) {
tty = pCh->pTTY;
if (tty && tty->count) {
- len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags,
+ seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
tty->termios->c_cflag,tty->termios->c_iflag);
- len += sprintf(buf+len,FMTLIN2,
+ seq_printf(m,FMTLIN2,
pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
- len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room);
+ seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
}
}
}
- return len;
+ return 0;
+}
+
+static int proc_ip2mem_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_ip2mem_show, NULL);
}
+static const struct file_operations ip2mem_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_ip2mem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*
* This is the handler for /proc/tty/driver/ip2
*
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 553f0a408eda..eb8a1a8c188e 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -9,7 +9,3 @@ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
-
-ipmi_si.o: $(ipmi_si-objs)
- $(LD) -r -o $@ $(ipmi_si-objs)
-
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index e736119b6497..7b98c067190a 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -37,26 +37,32 @@
#define BT_DEBUG_ENABLE 1 /* Generic messages */
#define BT_DEBUG_MSG 2 /* Prints all request/response buffers */
#define BT_DEBUG_STATES 4 /* Verbose look at state changes */
-/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized
- value */
+/*
+ * BT_DEBUG_OFF must be zero to correspond to the default uninitialized
+ * value
+ */
static int bt_debug; /* 0 == BT_DEBUG_OFF */
module_param(bt_debug, int, 0644);
MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
-/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
- and 64 byte buffers. However, one HP implementation wants 255 bytes of
- buffer (with a documented message of 160 bytes) so go for the max.
- Since the Open IPMI architecture is single-message oriented at this
- stage, the queue depth of BT is of no concern. */
+/*
+ * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
+ * and 64 byte buffers. However, one HP implementation wants 255 bytes of
+ * buffer (with a documented message of 160 bytes) so go for the max.
+ * Since the Open IPMI architecture is single-message oriented at this
+ * stage, the queue depth of BT is of no concern.
+ */
#define BT_NORMAL_TIMEOUT 5 /* seconds */
#define BT_NORMAL_RETRY_LIMIT 2
#define BT_RESET_DELAY 6 /* seconds after warm reset */
-/* States are written in chronological order and usually cover
- multiple rows of the state table discussion in the IPMI spec. */
+/*
+ * States are written in chronological order and usually cover
+ * multiple rows of the state table discussion in the IPMI spec.
+ */
enum bt_states {
BT_STATE_IDLE = 0, /* Order is critical in this list */
@@ -76,10 +82,12 @@ enum bt_states {
BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */
};
-/* Macros seen at the end of state "case" blocks. They help with legibility
- and debugging. */
+/*
+ * Macros seen at the end of state "case" blocks. They help with legibility
+ * and debugging.
+ */
-#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; }
+#define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; }
#define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; }
@@ -110,11 +118,13 @@ struct si_sm_data {
#define BT_H_BUSY 0x40
#define BT_B_BUSY 0x80
-/* Some bits are toggled on each write: write once to set it, once
- more to clear it; writing a zero does nothing. To absolutely
- clear it, check its state and write if set. This avoids the "get
- current then use as mask" scheme to modify one bit. Note that the
- variable "bt" is hardcoded into these macros. */
+/*
+ * Some bits are toggled on each write: write once to set it, once
+ * more to clear it; writing a zero does nothing. To absolutely
+ * clear it, check its state and write if set. This avoids the "get
+ * current then use as mask" scheme to modify one bit. Note that the
+ * variable "bt" is hardcoded into these macros.
+ */
#define BT_STATUS bt->io->inputb(bt->io, 0)
#define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x)
@@ -125,8 +135,10 @@ struct si_sm_data {
#define BT_INTMASK_R bt->io->inputb(bt->io, 2)
#define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
-/* Convenience routines for debugging. These are not multi-open safe!
- Note the macros have hardcoded variables in them. */
+/*
+ * Convenience routines for debugging. These are not multi-open safe!
+ * Note the macros have hardcoded variables in them.
+ */
static char *state2txt(unsigned char state)
{
@@ -182,7 +194,8 @@ static char *status2txt(unsigned char status)
static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
{
memset(bt, 0, sizeof(struct si_sm_data));
- if (bt->io != io) { /* external: one-time only things */
+ if (bt->io != io) {
+ /* external: one-time only things */
bt->io = io;
bt->seq = 0;
}
@@ -229,7 +242,7 @@ static int bt_start_transaction(struct si_sm_data *bt,
printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
for (i = 0; i < size; i ++)
- printk (" %02x", data[i]);
+ printk(" %02x", data[i]);
printk("\n");
}
bt->write_data[0] = size + 1; /* all data plus seq byte */
@@ -246,8 +259,10 @@ static int bt_start_transaction(struct si_sm_data *bt,
return 0;
}
-/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
- it calls this. Strip out the length and seq bytes. */
+/*
+ * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
+ * it calls this. Strip out the length and seq bytes.
+ */
static int bt_get_result(struct si_sm_data *bt,
unsigned char *data,
@@ -269,10 +284,10 @@ static int bt_get_result(struct si_sm_data *bt,
memcpy(data + 2, bt->read_data + 4, msg_len - 2);
if (bt_debug & BT_DEBUG_MSG) {
- printk (KERN_WARNING "BT: result %d bytes:", msg_len);
+ printk(KERN_WARNING "BT: result %d bytes:", msg_len);
for (i = 0; i < msg_len; i++)
printk(" %02x", data[i]);
- printk ("\n");
+ printk("\n");
}
return msg_len;
}
@@ -292,8 +307,10 @@ static void reset_flags(struct si_sm_data *bt)
BT_INTMASK_W(BT_BMC_HWRST);
}
-/* Get rid of an unwanted/stale response. This should only be needed for
- BMCs that support multiple outstanding requests. */
+/*
+ * Get rid of an unwanted/stale response. This should only be needed for
+ * BMCs that support multiple outstanding requests.
+ */
static void drain_BMC2HOST(struct si_sm_data *bt)
{
@@ -326,8 +343,8 @@ static inline void write_all_bytes(struct si_sm_data *bt)
printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
bt->write_count, bt->seq);
for (i = 0; i < bt->write_count; i++)
- printk (" %02x", bt->write_data[i]);
- printk ("\n");
+ printk(" %02x", bt->write_data[i]);
+ printk("\n");
}
for (i = 0; i < bt->write_count; i++)
HOST2BMC(bt->write_data[i]);
@@ -337,8 +354,10 @@ static inline int read_all_bytes(struct si_sm_data *bt)
{
unsigned char i;
- /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
- Keep layout of first four bytes aligned with write_data[] */
+ /*
+ * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
+ * Keep layout of first four bytes aligned with write_data[]
+ */
bt->read_data[0] = BMC2HOST;
bt->read_count = bt->read_data[0];
@@ -362,8 +381,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
if (max > 16)
max = 16;
for (i = 0; i < max; i++)
- printk (" %02x", bt->read_data[i]);
- printk ("%s\n", bt->read_count == max ? "" : " ...");
+ printk(KERN_CONT " %02x", bt->read_data[i]);
+ printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ...");
}
/* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */
@@ -402,8 +421,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt,
printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */
reason, STATE2TXT, STATUS2TXT);
- /* Per the IPMI spec, retries are based on the sequence number
- known only to this module, so manage a restart here. */
+ /*
+ * Per the IPMI spec, retries are based on the sequence number
+ * known only to this module, so manage a restart here.
+ */
(bt->error_retries)++;
if (bt->error_retries < bt->BT_CAP_retries) {
printk("%d retries left\n",
@@ -412,8 +433,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt,
return SI_SM_CALL_WITHOUT_DELAY;
}
- printk("failed %d retries, sending error response\n",
- bt->BT_CAP_retries);
+ printk(KERN_WARNING "failed %d retries, sending error response\n",
+ bt->BT_CAP_retries);
if (!bt->nonzero_status)
printk(KERN_ERR "IPMI BT: stuck, try power cycle\n");
@@ -424,8 +445,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt,
return SI_SM_CALL_WITHOUT_DELAY;
}
- /* Concoct a useful error message, set up the next state, and
- be done with this sequence. */
+ /*
+ * Concoct a useful error message, set up the next state, and
+ * be done with this sequence.
+ */
bt->state = BT_STATE_IDLE;
switch (cCode) {
@@ -461,10 +484,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
last_printed = bt->state;
}
- /* Commands that time out may still (eventually) provide a response.
- This stale response will get in the way of a new response so remove
- it if possible (hopefully during IDLE). Even if it comes up later
- it will be rejected by its (now-forgotten) seq number. */
+ /*
+ * Commands that time out may still (eventually) provide a response.
+ * This stale response will get in the way of a new response so remove
+ * it if possible (hopefully during IDLE). Even if it comes up later
+ * it will be rejected by its (now-forgotten) seq number.
+ */
if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
drain_BMC2HOST(bt);
@@ -472,7 +497,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
}
if ((bt->state != BT_STATE_IDLE) &&
- (bt->state < BT_STATE_PRINTME)) { /* check timeout */
+ (bt->state < BT_STATE_PRINTME)) {
+ /* check timeout */
bt->timeout -= time;
if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
return error_recovery(bt,
@@ -482,8 +508,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
switch (bt->state) {
- /* Idle state first checks for asynchronous messages from another
- channel, then does some opportunistic housekeeping. */
+ /*
+ * Idle state first checks for asynchronous messages from another
+ * channel, then does some opportunistic housekeeping.
+ */
case BT_STATE_IDLE:
if (status & BT_SMS_ATN) {
@@ -531,16 +559,19 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
BT_CONTROL(BT_H_BUSY); /* set */
- /* Uncached, ordered writes should just proceeed serially but
- some BMCs don't clear B2H_ATN with one hit. Fast-path a
- workaround without too much penalty to the general case. */
+ /*
+ * Uncached, ordered writes should just proceeed serially but
+ * some BMCs don't clear B2H_ATN with one hit. Fast-path a
+ * workaround without too much penalty to the general case.
+ */
BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */
BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_CLEAR_B2H:
- if (status & BT_B2H_ATN) { /* keep hitting it */
+ if (status & BT_B2H_ATN) {
+ /* keep hitting it */
BT_CONTROL(BT_B2H_ATN);
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
}
@@ -548,7 +579,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_READ_BYTES:
- if (!(status & BT_H_BUSY)) /* check in case of retry */
+ if (!(status & BT_H_BUSY))
+ /* check in case of retry */
BT_CONTROL(BT_H_BUSY);
BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */
i = read_all_bytes(bt); /* true == packet seq match */
@@ -599,8 +631,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
BT_STATE_CHANGE(BT_STATE_XACTION_START,
SI_SM_CALL_WITH_DELAY);
- /* Get BT Capabilities, using timing of upper level state machine.
- Set outreqs to prevent infinite loop on timeout. */
+ /*
+ * Get BT Capabilities, using timing of upper level state machine.
+ * Set outreqs to prevent infinite loop on timeout.
+ */
case BT_STATE_CAPABILITIES_BEGIN:
bt->BT_CAP_outreqs = 1;
{
@@ -638,10 +672,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
static int bt_detect(struct si_sm_data *bt)
{
- /* It's impossible for the BT status and interrupt registers to be
- all 1's, (assuming a properly functioning, self-initialized BMC)
- but that's what you get from reading a bogus address, so we
- test that first. The calling routine uses negative logic. */
+ /*
+ * It's impossible for the BT status and interrupt registers to be
+ * all 1's, (assuming a properly functioning, self-initialized BMC)
+ * but that's what you get from reading a bogus address, so we
+ * test that first. The calling routine uses negative logic.
+ */
if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
return 1;
@@ -658,8 +694,7 @@ static int bt_size(void)
return sizeof(struct si_sm_data);
}
-struct si_sm_handlers bt_smi_handlers =
-{
+struct si_sm_handlers bt_smi_handlers = {
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index c1b8228cb7b6..80704875794c 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -60,37 +60,58 @@ MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
/* The states the KCS driver may be in. */
enum kcs_states {
- KCS_IDLE, /* The KCS interface is currently
- doing nothing. */
- KCS_START_OP, /* We are starting an operation. The
- data is in the output buffer, but
- nothing has been done to the
- interface yet. This was added to
- the state machine in the spec to
- wait for the initial IBF. */
- KCS_WAIT_WRITE_START, /* We have written a write cmd to the
- interface. */
- KCS_WAIT_WRITE, /* We are writing bytes to the
- interface. */
- KCS_WAIT_WRITE_END, /* We have written the write end cmd
- to the interface, and still need to
- write the last byte. */
- KCS_WAIT_READ, /* We are waiting to read data from
- the interface. */
- KCS_ERROR0, /* State to transition to the error
- handler, this was added to the
- state machine in the spec to be
- sure IBF was there. */
- KCS_ERROR1, /* First stage error handler, wait for
- the interface to respond. */
- KCS_ERROR2, /* The abort cmd has been written,
- wait for the interface to
- respond. */
- KCS_ERROR3, /* We wrote some data to the
- interface, wait for it to switch to
- read mode. */
- KCS_HOSED /* The hardware failed to follow the
- state machine. */
+ /* The KCS interface is currently doing nothing. */
+ KCS_IDLE,
+
+ /*
+ * We are starting an operation. The data is in the output
+ * buffer, but nothing has been done to the interface yet. This
+ * was added to the state machine in the spec to wait for the
+ * initial IBF.
+ */
+ KCS_START_OP,
+
+ /* We have written a write cmd to the interface. */
+ KCS_WAIT_WRITE_START,
+
+ /* We are writing bytes to the interface. */
+ KCS_WAIT_WRITE,
+
+ /*
+ * We have written the write end cmd to the interface, and
+ * still need to write the last byte.
+ */
+ KCS_WAIT_WRITE_END,
+
+ /* We are waiting to read data from the interface. */
+ KCS_WAIT_READ,
+
+ /*
+ * State to transition to the error handler, this was added to
+ * the state machine in the spec to be sure IBF was there.
+ */
+ KCS_ERROR0,
+
+ /*
+ * First stage error handler, wait for the interface to
+ * respond.
+ */
+ KCS_ERROR1,
+
+ /*
+ * The abort cmd has been written, wait for the interface to
+ * respond.
+ */
+ KCS_ERROR2,
+
+ /*
+ * We wrote some data to the interface, wait for it to switch
+ * to read mode.
+ */
+ KCS_ERROR3,
+
+ /* The hardware failed to follow the state machine. */
+ KCS_HOSED
};
#define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH
@@ -102,8 +123,7 @@ enum kcs_states {
#define MAX_ERROR_RETRIES 10
#define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
-struct si_sm_data
-{
+struct si_sm_data {
enum kcs_states state;
struct si_sm_io *io;
unsigned char write_data[MAX_KCS_WRITE_SIZE];
@@ -187,7 +207,8 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
(kcs->error_retries)++;
if (kcs->error_retries > MAX_ERROR_RETRIES) {
if (kcs_debug & KCS_DEBUG_ENABLE)
- printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason);
+ printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n",
+ reason);
kcs->state = KCS_HOSED;
} else {
kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES;
@@ -271,10 +292,9 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
if (kcs_debug & KCS_DEBUG_MSG) {
printk(KERN_DEBUG "start_kcs_transaction -");
- for (i = 0; i < size; i ++) {
+ for (i = 0; i < size; i++)
printk(" %02x", (unsigned char) (data [i]));
- }
- printk ("\n");
+ printk("\n");
}
kcs->error_retries = 0;
memcpy(kcs->write_data, data, size);
@@ -305,9 +325,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data,
kcs->read_pos = 3;
}
if (kcs->truncated) {
- /* Report a truncated error. We might overwrite
- another error, but that's too bad, the user needs
- to know it was truncated. */
+ /*
+ * Report a truncated error. We might overwrite
+ * another error, but that's too bad, the user needs
+ * to know it was truncated.
+ */
data[2] = IPMI_ERR_MSG_TRUNCATED;
kcs->truncated = 0;
}
@@ -315,9 +337,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data,
return kcs->read_pos;
}
-/* This implements the state machine defined in the IPMI manual, see
- that for details on how this works. Divide that flowchart into
- sections delimited by "Wait for IBF" and this will become clear. */
+/*
+ * This implements the state machine defined in the IPMI manual, see
+ * that for details on how this works. Divide that flowchart into
+ * sections delimited by "Wait for IBF" and this will become clear.
+ */
static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
{
unsigned char status;
@@ -388,11 +412,12 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
write_next_byte(kcs);
}
break;
-
+
case KCS_WAIT_WRITE_END:
if (state != KCS_WRITE_STATE) {
start_error_recovery(kcs,
- "Not in write state for write end");
+ "Not in write state"
+ " for write end");
break;
}
clear_obf(kcs, status);
@@ -413,13 +438,15 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
return SI_SM_CALL_WITH_DELAY;
read_next_byte(kcs);
} else {
- /* We don't implement this exactly like the state
- machine in the spec. Some broken hardware
- does not write the final dummy byte to the
- read register. Thus obf will never go high
- here. We just go straight to idle, and we
- handle clearing out obf in idle state if it
- happens to come in. */
+ /*
+ * We don't implement this exactly like the state
+ * machine in the spec. Some broken hardware
+ * does not write the final dummy byte to the
+ * read register. Thus obf will never go high
+ * here. We just go straight to idle, and we
+ * handle clearing out obf in idle state if it
+ * happens to come in.
+ */
clear_obf(kcs, status);
kcs->orig_write_count = 0;
kcs->state = KCS_IDLE;
@@ -430,7 +457,8 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
case KCS_ERROR0:
clear_obf(kcs, status);
status = read_status(kcs);
- if (GET_STATUS_OBF(status)) /* controller isn't responding */
+ if (GET_STATUS_OBF(status))
+ /* controller isn't responding */
if (time_before(jiffies, kcs->error0_timeout))
return SI_SM_CALL_WITH_TICK_DELAY;
write_cmd(kcs, KCS_GET_STATUS_ABORT);
@@ -442,7 +470,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
write_data(kcs, 0);
kcs->state = KCS_ERROR2;
break;
-
+
case KCS_ERROR2:
if (state != KCS_READ_STATE) {
start_error_recovery(kcs,
@@ -456,7 +484,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
write_data(kcs, KCS_READ_BYTE);
kcs->state = KCS_ERROR3;
break;
-
+
case KCS_ERROR3:
if (state != KCS_IDLE_STATE) {
start_error_recovery(kcs,
@@ -475,7 +503,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
return SI_SM_TRANSACTION_COMPLETE;
}
break;
-
+
case KCS_HOSED:
break;
}
@@ -495,10 +523,12 @@ static int kcs_size(void)
static int kcs_detect(struct si_sm_data *kcs)
{
- /* It's impossible for the KCS status register to be all 1's,
- (assuming a properly functioning, self-initialized BMC)
- but that's what you get from reading a bogus address, so we
- test that first. */
+ /*
+ * It's impossible for the KCS status register to be all 1's,
+ * (assuming a properly functioning, self-initialized BMC)
+ * but that's what you get from reading a bogus address, so we
+ * test that first.
+ */
if (read_status(kcs) == 0xff)
return 1;
@@ -509,8 +539,7 @@ static void kcs_cleanup(struct si_sm_data *kcs)
{
}
-struct si_sm_handlers kcs_smi_handlers =
-{
+struct si_sm_handlers kcs_smi_handlers = {
.init_data = init_kcs_data,
.start_transaction = start_kcs_transaction,
.get_result = get_kcs_result,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 32b2b22996dc..8a59aaa21be5 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -47,7 +47,7 @@
#define PFX "IPMI message handler: "
-#define IPMI_DRIVER_VERSION "39.1"
+#define IPMI_DRIVER_VERSION "39.2"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
@@ -63,16 +63,16 @@ static struct proc_dir_entry *proc_ipmi_root;
#define MAX_EVENTS_IN_QUEUE 25
-/* Don't let a message sit in a queue forever, always time it with at lest
- the max message timer. This is in milliseconds. */
+/*
+ * Don't let a message sit in a queue forever, always time it with at lest
+ * the max message timer. This is in milliseconds.
+ */
#define MAX_MSG_TIMEOUT 60000
-
/*
* The main "user" data structure.
*/
-struct ipmi_user
-{
+struct ipmi_user {
struct list_head link;
/* Set to "0" when the user is destroyed. */
@@ -91,8 +91,7 @@ struct ipmi_user
int gets_events;
};
-struct cmd_rcvr
-{
+struct cmd_rcvr {
struct list_head link;
ipmi_user_t user;
@@ -106,12 +105,12 @@ struct cmd_rcvr
* or change any data until the RCU period completes. So we
* use this next variable during mass deletion so we can have
* a list and don't have to wait and restart the search on
- * every individual deletion of a command. */
+ * every individual deletion of a command.
+ */
struct cmd_rcvr *next;
};
-struct seq_table
-{
+struct seq_table {
unsigned int inuse : 1;
unsigned int broadcast : 1;
@@ -119,53 +118,60 @@ struct seq_table
unsigned long orig_timeout;
unsigned int retries_left;
- /* To verify on an incoming send message response that this is
- the message that the response is for, we keep a sequence id
- and increment it every time we send a message. */
+ /*
+ * To verify on an incoming send message response that this is
+ * the message that the response is for, we keep a sequence id
+ * and increment it every time we send a message.
+ */
long seqid;
- /* This is held so we can properly respond to the message on a
- timeout, and it is used to hold the temporary data for
- retransmission, too. */
+ /*
+ * This is held so we can properly respond to the message on a
+ * timeout, and it is used to hold the temporary data for
+ * retransmission, too.
+ */
struct ipmi_recv_msg *recv_msg;
};
-/* Store the information in a msgid (long) to allow us to find a
- sequence table entry from the msgid. */
+/*
+ * Store the information in a msgid (long) to allow us to find a
+ * sequence table entry from the msgid.
+ */
#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
do { \
seq = ((msgid >> 26) & 0x3f); \
seqid = (msgid & 0x3fffff); \
- } while (0)
+ } while (0)
#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
-struct ipmi_channel
-{
+struct ipmi_channel {
unsigned char medium;
unsigned char protocol;
- /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
- but may be changed by the user. */
+ /*
+ * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
+ * but may be changed by the user.
+ */
unsigned char address;
- /* My LUN. This should generally stay the SMS LUN, but just in
- case... */
+ /*
+ * My LUN. This should generally stay the SMS LUN, but just in
+ * case...
+ */
unsigned char lun;
};
#ifdef CONFIG_PROC_FS
-struct ipmi_proc_entry
-{
+struct ipmi_proc_entry {
char *name;
struct ipmi_proc_entry *next;
};
#endif
-struct bmc_device
-{
+struct bmc_device {
struct platform_device *dev;
struct ipmi_device_id id;
unsigned char guid[16];
@@ -186,10 +192,108 @@ struct bmc_device
struct device_attribute aux_firmware_rev_attr;
};
+/*
+ * Various statistics for IPMI, these index stats[] in the ipmi_smi
+ * structure.
+ */
+enum ipmi_stat_indexes {
+ /* Commands we got from the user that were invalid. */
+ IPMI_STAT_sent_invalid_commands = 0,
+
+ /* Commands we sent to the MC. */
+ IPMI_STAT_sent_local_commands,
+
+ /* Responses from the MC that were delivered to a user. */
+ IPMI_STAT_handled_local_responses,
+
+ /* Responses from the MC that were not delivered to a user. */
+ IPMI_STAT_unhandled_local_responses,
+
+ /* Commands we sent out to the IPMB bus. */
+ IPMI_STAT_sent_ipmb_commands,
+
+ /* Commands sent on the IPMB that had errors on the SEND CMD */
+ IPMI_STAT_sent_ipmb_command_errs,
+
+ /* Each retransmit increments this count. */
+ IPMI_STAT_retransmitted_ipmb_commands,
+
+ /*
+ * When a message times out (runs out of retransmits) this is
+ * incremented.
+ */
+ IPMI_STAT_timed_out_ipmb_commands,
+
+ /*
+ * This is like above, but for broadcasts. Broadcasts are
+ * *not* included in the above count (they are expected to
+ * time out).
+ */
+ IPMI_STAT_timed_out_ipmb_broadcasts,
+
+ /* Responses I have sent to the IPMB bus. */
+ IPMI_STAT_sent_ipmb_responses,
+
+ /* The response was delivered to the user. */
+ IPMI_STAT_handled_ipmb_responses,
+
+ /* The response had invalid data in it. */
+ IPMI_STAT_invalid_ipmb_responses,
+
+ /* The response didn't have anyone waiting for it. */
+ IPMI_STAT_unhandled_ipmb_responses,
+
+ /* Commands we sent out to the IPMB bus. */
+ IPMI_STAT_sent_lan_commands,
+
+ /* Commands sent on the IPMB that had errors on the SEND CMD */
+ IPMI_STAT_sent_lan_command_errs,
+
+ /* Each retransmit increments this count. */
+ IPMI_STAT_retransmitted_lan_commands,
+
+ /*
+ * When a message times out (runs out of retransmits) this is
+ * incremented.
+ */
+ IPMI_STAT_timed_out_lan_commands,
+
+ /* Responses I have sent to the IPMB bus. */
+ IPMI_STAT_sent_lan_responses,
+
+ /* The response was delivered to the user. */
+ IPMI_STAT_handled_lan_responses,
+
+ /* The response had invalid data in it. */
+ IPMI_STAT_invalid_lan_responses,
+
+ /* The response didn't have anyone waiting for it. */
+ IPMI_STAT_unhandled_lan_responses,
+
+ /* The command was delivered to the user. */
+ IPMI_STAT_handled_commands,
+
+ /* The command had invalid data in it. */
+ IPMI_STAT_invalid_commands,
+
+ /* The command didn't have anyone waiting for it. */
+ IPMI_STAT_unhandled_commands,
+
+ /* Invalid data in an event. */
+ IPMI_STAT_invalid_events,
+
+ /* Events that were received with the proper format. */
+ IPMI_STAT_events,
+
+
+ /* This *must* remain last, add new values above this. */
+ IPMI_NUM_STATS
+};
+
+
#define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 16
-struct ipmi_smi
-{
+struct ipmi_smi {
/* What interface number are we? */
int intf_num;
@@ -198,8 +302,10 @@ struct ipmi_smi
/* Used for a list of interfaces. */
struct list_head link;
- /* The list of upper layers that are using me. seq_lock
- * protects this. */
+ /*
+ * The list of upper layers that are using me. seq_lock
+ * protects this.
+ */
struct list_head users;
/* Information to supply to users. */
@@ -213,10 +319,12 @@ struct ipmi_smi
char *my_dev_name;
char *sysfs_name;
- /* This is the lower-layer's sender routine. Note that you
+ /*
+ * This is the lower-layer's sender routine. Note that you
* must either be holding the ipmi_interfaces_mutex or be in
* an umpreemptible region to use this. You must fetch the
- * value into a local variable and make sure it is not NULL. */
+ * value into a local variable and make sure it is not NULL.
+ */
struct ipmi_smi_handlers *handlers;
void *send_info;
@@ -229,34 +337,45 @@ struct ipmi_smi
/* Driver-model device for the system interface. */
struct device *si_dev;
- /* A table of sequence numbers for this interface. We use the
- sequence numbers for IPMB messages that go out of the
- interface to match them up with their responses. A routine
- is called periodically to time the items in this list. */
+ /*
+ * A table of sequence numbers for this interface. We use the
+ * sequence numbers for IPMB messages that go out of the
+ * interface to match them up with their responses. A routine
+ * is called periodically to time the items in this list.
+ */
spinlock_t seq_lock;
struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
int curr_seq;
- /* Messages that were delayed for some reason (out of memory,
- for instance), will go in here to be processed later in a
- periodic timer interrupt. */
+ /*
+ * Messages that were delayed for some reason (out of memory,
+ * for instance), will go in here to be processed later in a
+ * periodic timer interrupt.
+ */
spinlock_t waiting_msgs_lock;
struct list_head waiting_msgs;
- /* The list of command receivers that are registered for commands
- on this interface. */
+ /*
+ * The list of command receivers that are registered for commands
+ * on this interface.
+ */
struct mutex cmd_rcvrs_mutex;
struct list_head cmd_rcvrs;
- /* Events that were queues because no one was there to receive
- them. */
+ /*
+ * Events that were queues because no one was there to receive
+ * them.
+ */
spinlock_t events_lock; /* For dealing with event stuff. */
struct list_head waiting_events;
unsigned int waiting_events_count; /* How many events in queue? */
- int delivering_events;
+ char delivering_events;
+ char event_msg_printed;
- /* The event receiver for my BMC, only really used at panic
- shutdown as a place to store this. */
+ /*
+ * The event receiver for my BMC, only really used at panic
+ * shutdown as a place to store this.
+ */
unsigned char event_receiver;
unsigned char event_receiver_lun;
unsigned char local_sel_device;
@@ -268,14 +387,18 @@ struct ipmi_smi
int auto_maintenance_timeout;
spinlock_t maintenance_mode_lock; /* Used in a timer... */
- /* A cheap hack, if this is non-null and a message to an
- interface comes in with a NULL user, call this routine with
- it. Note that the message will still be freed by the
- caller. This only works on the system interface. */
+ /*
+ * A cheap hack, if this is non-null and a message to an
+ * interface comes in with a NULL user, call this routine with
+ * it. Note that the message will still be freed by the
+ * caller. This only works on the system interface.
+ */
void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
- /* When we are scanning the channels for an SMI, this will
- tell which channel we are scanning. */
+ /*
+ * When we are scanning the channels for an SMI, this will
+ * tell which channel we are scanning.
+ */
int curr_channel;
/* Channel information */
@@ -285,74 +408,14 @@ struct ipmi_smi
struct proc_dir_entry *proc_dir;
char proc_dir_name[10];
- spinlock_t counter_lock; /* For making counters atomic. */
-
- /* Commands we got that were invalid. */
- unsigned int sent_invalid_commands;
-
- /* Commands we sent to the MC. */
- unsigned int sent_local_commands;
- /* Responses from the MC that were delivered to a user. */
- unsigned int handled_local_responses;
- /* Responses from the MC that were not delivered to a user. */
- unsigned int unhandled_local_responses;
-
- /* Commands we sent out to the IPMB bus. */
- unsigned int sent_ipmb_commands;
- /* Commands sent on the IPMB that had errors on the SEND CMD */
- unsigned int sent_ipmb_command_errs;
- /* Each retransmit increments this count. */
- unsigned int retransmitted_ipmb_commands;
- /* When a message times out (runs out of retransmits) this is
- incremented. */
- unsigned int timed_out_ipmb_commands;
-
- /* This is like above, but for broadcasts. Broadcasts are
- *not* included in the above count (they are expected to
- time out). */
- unsigned int timed_out_ipmb_broadcasts;
+ atomic_t stats[IPMI_NUM_STATS];
- /* Responses I have sent to the IPMB bus. */
- unsigned int sent_ipmb_responses;
-
- /* The response was delivered to the user. */
- unsigned int handled_ipmb_responses;
- /* The response had invalid data in it. */
- unsigned int invalid_ipmb_responses;
- /* The response didn't have anyone waiting for it. */
- unsigned int unhandled_ipmb_responses;
-
- /* Commands we sent out to the IPMB bus. */
- unsigned int sent_lan_commands;
- /* Commands sent on the IPMB that had errors on the SEND CMD */
- unsigned int sent_lan_command_errs;
- /* Each retransmit increments this count. */
- unsigned int retransmitted_lan_commands;
- /* When a message times out (runs out of retransmits) this is
- incremented. */
- unsigned int timed_out_lan_commands;
-
- /* Responses I have sent to the IPMB bus. */
- unsigned int sent_lan_responses;
-
- /* The response was delivered to the user. */
- unsigned int handled_lan_responses;
- /* The response had invalid data in it. */
- unsigned int invalid_lan_responses;
- /* The response didn't have anyone waiting for it. */
- unsigned int unhandled_lan_responses;
-
- /* The command was delivered to the user. */
- unsigned int handled_commands;
- /* The command had invalid data in it. */
- unsigned int invalid_commands;
- /* The command didn't have anyone waiting for it. */
- unsigned int unhandled_commands;
-
- /* Invalid data in an event. */
- unsigned int invalid_events;
- /* Events that were received with the proper format. */
- unsigned int events;
+ /*
+ * run_to_completion duplicate of smb_info, smi_info
+ * and ipmi_serial_info structures. Used to decrease numbers of
+ * parameters passed by "low" level IPMI code.
+ */
+ int run_to_completion;
};
#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
@@ -368,12 +431,19 @@ static DEFINE_MUTEX(ipmidriver_mutex);
static LIST_HEAD(ipmi_interfaces);
static DEFINE_MUTEX(ipmi_interfaces_mutex);
-/* List of watchers that want to know when smi's are added and
- deleted. */
+/*
+ * List of watchers that want to know when smi's are added and deleted.
+ */
static LIST_HEAD(smi_watchers);
static DEFINE_MUTEX(smi_watchers_mutex);
+#define ipmi_inc_stat(intf, stat) \
+ atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat])
+#define ipmi_get_stat(intf, stat) \
+ ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat]))
+
+
static void free_recv_msg_list(struct list_head *q)
{
struct ipmi_recv_msg *msg, *msg2;
@@ -417,10 +487,8 @@ static void clean_up_interface_data(ipmi_smi_t intf)
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if ((intf->seq_table[i].inuse)
- && (intf->seq_table[i].recv_msg))
- {
+ && (intf->seq_table[i].recv_msg))
ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
- }
}
}
@@ -487,6 +555,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
}
return -ENOMEM;
}
+EXPORT_SYMBOL(ipmi_smi_watcher_register);
int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
{
@@ -495,6 +564,7 @@ int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
mutex_unlock(&smi_watchers_mutex);
return 0;
}
+EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
/*
* Must be called with smi_watchers_mutex held.
@@ -530,8 +600,7 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
}
if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
+ || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
struct ipmi_ipmb_addr *ipmb_addr1
= (struct ipmi_ipmb_addr *) addr1;
struct ipmi_ipmb_addr *ipmb_addr2
@@ -559,9 +628,8 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
int ipmi_validate_addr(struct ipmi_addr *addr, int len)
{
- if (len < sizeof(struct ipmi_system_interface_addr)) {
+ if (len < sizeof(struct ipmi_system_interface_addr))
return -EINVAL;
- }
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
if (addr->channel != IPMI_BMC_CHANNEL)
@@ -575,23 +643,21 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len)
return -EINVAL;
if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
- if (len < sizeof(struct ipmi_ipmb_addr)) {
+ || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
+ if (len < sizeof(struct ipmi_ipmb_addr))
return -EINVAL;
- }
return 0;
}
if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
- if (len < sizeof(struct ipmi_lan_addr)) {
+ if (len < sizeof(struct ipmi_lan_addr))
return -EINVAL;
- }
return 0;
}
return -EINVAL;
}
+EXPORT_SYMBOL(ipmi_validate_addr);
unsigned int ipmi_addr_length(int addr_type)
{
@@ -599,34 +665,28 @@ unsigned int ipmi_addr_length(int addr_type)
return sizeof(struct ipmi_system_interface_addr);
if ((addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
+ || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
return sizeof(struct ipmi_ipmb_addr);
- }
if (addr_type == IPMI_LAN_ADDR_TYPE)
return sizeof(struct ipmi_lan_addr);
return 0;
}
+EXPORT_SYMBOL(ipmi_addr_length);
static void deliver_response(struct ipmi_recv_msg *msg)
{
if (!msg->user) {
ipmi_smi_t intf = msg->user_msg_data;
- unsigned long flags;
/* Special handling for NULL users. */
if (intf->null_user_handler) {
intf->null_user_handler(intf, msg);
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_local_responses);
} else {
/* No handler, so give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, unhandled_local_responses);
}
ipmi_free_recv_msg(msg);
} else {
@@ -646,9 +706,11 @@ deliver_err_response(struct ipmi_recv_msg *msg, int err)
deliver_response(msg);
}
-/* Find the next sequence number not being used and add the given
- message with the given timeout to the sequence table. This must be
- called with the interface's seq_lock held. */
+/*
+ * Find the next sequence number not being used and add the given
+ * message with the given timeout to the sequence table. This must be
+ * called with the interface's seq_lock held.
+ */
static int intf_next_seq(ipmi_smi_t intf,
struct ipmi_recv_msg *recv_msg,
unsigned long timeout,
@@ -660,10 +722,8 @@ static int intf_next_seq(ipmi_smi_t intf,
int rv = 0;
unsigned int i;
- for (i = intf->curr_seq;
- (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
- i = (i+1)%IPMI_IPMB_NUM_SEQ)
- {
+ for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
+ i = (i+1)%IPMI_IPMB_NUM_SEQ) {
if (!intf->seq_table[i].inuse)
break;
}
@@ -671,8 +731,10 @@ static int intf_next_seq(ipmi_smi_t intf,
if (!intf->seq_table[i].inuse) {
intf->seq_table[i].recv_msg = recv_msg;
- /* Start with the maximum timeout, when the send response
- comes in we will start the real timer. */
+ /*
+ * Start with the maximum timeout, when the send response
+ * comes in we will start the real timer.
+ */
intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
intf->seq_table[i].orig_timeout = timeout;
intf->seq_table[i].retries_left = retries;
@@ -685,15 +747,17 @@ static int intf_next_seq(ipmi_smi_t intf,
} else {
rv = -EAGAIN;
}
-
+
return rv;
}
-/* Return the receive message for the given sequence number and
- release the sequence number so it can be reused. Some other data
- is passed in to be sure the message matches up correctly (to help
- guard against message coming in after their timeout and the
- sequence number being reused). */
+/*
+ * Return the receive message for the given sequence number and
+ * release the sequence number so it can be reused. Some other data
+ * is passed in to be sure the message matches up correctly (to help
+ * guard against message coming in after their timeout and the
+ * sequence number being reused).
+ */
static int intf_find_seq(ipmi_smi_t intf,
unsigned char seq,
short channel,
@@ -712,11 +776,9 @@ static int intf_find_seq(ipmi_smi_t intf,
if (intf->seq_table[seq].inuse) {
struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
- if ((msg->addr.channel == channel)
- && (msg->msg.cmd == cmd)
- && (msg->msg.netfn == netfn)
- && (ipmi_addr_equal(addr, &(msg->addr))))
- {
+ if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd)
+ && (msg->msg.netfn == netfn)
+ && (ipmi_addr_equal(addr, &(msg->addr)))) {
*recv_msg = msg;
intf->seq_table[seq].inuse = 0;
rv = 0;
@@ -741,11 +803,12 @@ static int intf_start_seq_timer(ipmi_smi_t intf,
GET_SEQ_FROM_MSGID(msgid, seq, seqid);
spin_lock_irqsave(&(intf->seq_lock), flags);
- /* We do this verification because the user can be deleted
- while a message is outstanding. */
+ /*
+ * We do this verification because the user can be deleted
+ * while a message is outstanding.
+ */
if ((intf->seq_table[seq].inuse)
- && (intf->seq_table[seq].seqid == seqid))
- {
+ && (intf->seq_table[seq].seqid == seqid)) {
struct seq_table *ent = &(intf->seq_table[seq]);
ent->timeout = ent->orig_timeout;
rv = 0;
@@ -770,11 +833,12 @@ static int intf_err_seq(ipmi_smi_t intf,
GET_SEQ_FROM_MSGID(msgid, seq, seqid);
spin_lock_irqsave(&(intf->seq_lock), flags);
- /* We do this verification because the user can be deleted
- while a message is outstanding. */
+ /*
+ * We do this verification because the user can be deleted
+ * while a message is outstanding.
+ */
if ((intf->seq_table[seq].inuse)
- && (intf->seq_table[seq].seqid == seqid))
- {
+ && (intf->seq_table[seq].seqid == seqid)) {
struct seq_table *ent = &(intf->seq_table[seq]);
ent->inuse = 0;
@@ -800,24 +864,30 @@ int ipmi_create_user(unsigned int if_num,
int rv = 0;
ipmi_smi_t intf;
- /* There is no module usecount here, because it's not
- required. Since this can only be used by and called from
- other modules, they will implicitly use this module, and
- thus this can't be removed unless the other modules are
- removed. */
+ /*
+ * There is no module usecount here, because it's not
+ * required. Since this can only be used by and called from
+ * other modules, they will implicitly use this module, and
+ * thus this can't be removed unless the other modules are
+ * removed.
+ */
if (handler == NULL)
return -EINVAL;
- /* Make sure the driver is actually initialized, this handles
- problems with initialization order. */
+ /*
+ * Make sure the driver is actually initialized, this handles
+ * problems with initialization order.
+ */
if (!initialized) {
rv = ipmi_init_msghandler();
if (rv)
return rv;
- /* The init code doesn't return an error if it was turned
- off, but it won't initialize. Check that. */
+ /*
+ * The init code doesn't return an error if it was turned
+ * off, but it won't initialize. Check that.
+ */
if (!initialized)
return -ENODEV;
}
@@ -858,8 +928,10 @@ int ipmi_create_user(unsigned int if_num,
}
}
- /* Hold the lock so intf->handlers is guaranteed to be good
- * until now */
+ /*
+ * Hold the lock so intf->handlers is guaranteed to be good
+ * until now
+ */
mutex_unlock(&ipmi_interfaces_mutex);
new_user->valid = 1;
@@ -876,6 +948,7 @@ out_kfree:
kfree(new_user);
return rv;
}
+EXPORT_SYMBOL(ipmi_create_user);
static void free_user(struct kref *ref)
{
@@ -899,8 +972,7 @@ int ipmi_destroy_user(ipmi_user_t user)
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if (intf->seq_table[i].inuse
- && (intf->seq_table[i].recv_msg->user == user))
- {
+ && (intf->seq_table[i].recv_msg->user == user)) {
intf->seq_table[i].inuse = 0;
ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
}
@@ -943,6 +1015,7 @@ int ipmi_destroy_user(ipmi_user_t user)
return 0;
}
+EXPORT_SYMBOL(ipmi_destroy_user);
void ipmi_get_version(ipmi_user_t user,
unsigned char *major,
@@ -951,6 +1024,7 @@ void ipmi_get_version(ipmi_user_t user,
*major = user->intf->ipmi_version_major;
*minor = user->intf->ipmi_version_minor;
}
+EXPORT_SYMBOL(ipmi_get_version);
int ipmi_set_my_address(ipmi_user_t user,
unsigned int channel,
@@ -961,6 +1035,7 @@ int ipmi_set_my_address(ipmi_user_t user,
user->intf->channels[channel].address = address;
return 0;
}
+EXPORT_SYMBOL(ipmi_set_my_address);
int ipmi_get_my_address(ipmi_user_t user,
unsigned int channel,
@@ -971,6 +1046,7 @@ int ipmi_get_my_address(ipmi_user_t user,
*address = user->intf->channels[channel].address;
return 0;
}
+EXPORT_SYMBOL(ipmi_get_my_address);
int ipmi_set_my_LUN(ipmi_user_t user,
unsigned int channel,
@@ -981,6 +1057,7 @@ int ipmi_set_my_LUN(ipmi_user_t user,
user->intf->channels[channel].lun = LUN & 0x3;
return 0;
}
+EXPORT_SYMBOL(ipmi_set_my_LUN);
int ipmi_get_my_LUN(ipmi_user_t user,
unsigned int channel,
@@ -991,6 +1068,7 @@ int ipmi_get_my_LUN(ipmi_user_t user,
*address = user->intf->channels[channel].lun;
return 0;
}
+EXPORT_SYMBOL(ipmi_get_my_LUN);
int ipmi_get_maintenance_mode(ipmi_user_t user)
{
@@ -1075,6 +1153,11 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
list_move_tail(&msg->link, &msgs);
intf->waiting_events_count = 0;
+ if (intf->event_msg_printed) {
+ printk(KERN_WARNING PFX "Event queue no longer"
+ " full\n");
+ intf->event_msg_printed = 0;
+ }
intf->delivering_events = 1;
spin_unlock_irqrestore(&intf->events_lock, flags);
@@ -1094,6 +1177,7 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
return 0;
}
+EXPORT_SYMBOL(ipmi_set_gets_events);
static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
unsigned char netfn,
@@ -1159,6 +1243,7 @@ int ipmi_register_for_cmd(ipmi_user_t user,
return rv;
}
+EXPORT_SYMBOL(ipmi_register_for_cmd);
int ipmi_unregister_for_cmd(ipmi_user_t user,
unsigned char netfn,
@@ -1196,19 +1281,13 @@ int ipmi_unregister_for_cmd(ipmi_user_t user,
}
return rv;
}
-
-void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
-{
- ipmi_smi_t intf = user->intf;
- if (intf->handlers)
- intf->handlers->set_run_to_completion(intf->send_info, val);
-}
+EXPORT_SYMBOL(ipmi_unregister_for_cmd);
static unsigned char
ipmb_checksum(unsigned char *data, int size)
{
unsigned char csum = 0;
-
+
for (; size > 0; size--, data++)
csum += *data;
@@ -1250,8 +1329,10 @@ static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg,
= ipmb_checksum(&(smi_msg->data[i+6]),
smi_msg->data_size-6);
- /* Add on the checksum size and the offset from the
- broadcast. */
+ /*
+ * Add on the checksum size and the offset from the
+ * broadcast.
+ */
smi_msg->data_size += 1 + i;
smi_msg->msgid = msgid;
@@ -1287,17 +1368,21 @@ static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
= ipmb_checksum(&(smi_msg->data[7]),
smi_msg->data_size-7);
- /* Add on the checksum size and the offset from the
- broadcast. */
+ /*
+ * Add on the checksum size and the offset from the
+ * broadcast.
+ */
smi_msg->data_size += 1;
smi_msg->msgid = msgid;
}
-/* Separate from ipmi_request so that the user does not have to be
- supplied in certain circumstances (mainly at panic time). If
- messages are supplied, they will be freed, even if an error
- occurs. */
+/*
+ * Separate from ipmi_request so that the user does not have to be
+ * supplied in certain circumstances (mainly at panic time). If
+ * messages are supplied, they will be freed, even if an error
+ * occurs.
+ */
static int i_ipmi_request(ipmi_user_t user,
ipmi_smi_t intf,
struct ipmi_addr *addr,
@@ -1319,19 +1404,18 @@ static int i_ipmi_request(ipmi_user_t user,
struct ipmi_smi_handlers *handlers;
- if (supplied_recv) {
+ if (supplied_recv)
recv_msg = supplied_recv;
- } else {
+ else {
recv_msg = ipmi_alloc_recv_msg();
- if (recv_msg == NULL) {
+ if (recv_msg == NULL)
return -ENOMEM;
- }
}
recv_msg->user_msg_data = user_msg_data;
- if (supplied_smi) {
+ if (supplied_smi)
smi_msg = (struct ipmi_smi_msg *) supplied_smi;
- } else {
+ else {
smi_msg = ipmi_alloc_smi_msg();
if (smi_msg == NULL) {
ipmi_free_recv_msg(recv_msg);
@@ -1350,8 +1434,10 @@ static int i_ipmi_request(ipmi_user_t user,
if (user)
kref_get(&user->refcount);
recv_msg->msgid = msgid;
- /* Store the message to send in the receive message so timeout
- responses can get the proper response data. */
+ /*
+ * Store the message to send in the receive message so timeout
+ * responses can get the proper response data.
+ */
recv_msg->msg = *msg;
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
@@ -1365,9 +1451,7 @@ static int i_ipmi_request(ipmi_user_t user,
smi_addr = (struct ipmi_system_interface_addr *) addr;
if (smi_addr->lun > 3) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1377,13 +1461,12 @@ static int i_ipmi_request(ipmi_user_t user,
if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
&& ((msg->cmd == IPMI_SEND_MSG_CMD)
|| (msg->cmd == IPMI_GET_MSG_CMD)
- || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
- {
- /* We don't let the user do these, since we manage
- the sequence numbers. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) {
+ /*
+ * We don't let the user do these, since we manage
+ * the sequence numbers.
+ */
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1391,14 +1474,12 @@ static int i_ipmi_request(ipmi_user_t user,
if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
&& ((msg->cmd == IPMI_COLD_RESET_CMD)
|| (msg->cmd == IPMI_WARM_RESET_CMD)))
- || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
- {
+ || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) {
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
intf->auto_maintenance_timeout
= IPMI_MAINTENANCE_MODE_TIMEOUT;
if (!intf->maintenance_mode
- && !intf->maintenance_mode_enable)
- {
+ && !intf->maintenance_mode_enable) {
intf->maintenance_mode_enable = 1;
maintenance_mode_update(intf);
}
@@ -1407,9 +1488,7 @@ static int i_ipmi_request(ipmi_user_t user,
}
if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE;
goto out_err;
}
@@ -1421,31 +1500,23 @@ static int i_ipmi_request(ipmi_user_t user,
if (msg->data_len > 0)
memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
smi_msg->data_size = msg->data_len + 2;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_local_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_local_commands);
} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
+ || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
struct ipmi_ipmb_addr *ipmb_addr;
unsigned char ipmb_seq;
long seqid;
int broadcast = 0;
if (addr->channel >= IPMI_MAX_CHANNELS) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
if (intf->channels[addr->channel].medium
- != IPMI_CHANNEL_MEDIUM_IPMB)
- {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ != IPMI_CHANNEL_MEDIUM_IPMB) {
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1457,9 +1528,11 @@ static int i_ipmi_request(ipmi_user_t user,
retries = 4;
}
if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
- /* Broadcasts add a zero at the beginning of the
- message, but otherwise is the same as an IPMB
- address. */
+ /*
+ * Broadcasts add a zero at the beginning of the
+ * message, but otherwise is the same as an IPMB
+ * address.
+ */
addr->addr_type = IPMI_IPMB_ADDR_TYPE;
broadcast = 1;
}
@@ -1469,21 +1542,19 @@ static int i_ipmi_request(ipmi_user_t user,
if (retry_time_ms == 0)
retry_time_ms = 1000;
- /* 9 for the header and 1 for the checksum, plus
- possibly one for the broadcast. */
+ /*
+ * 9 for the header and 1 for the checksum, plus
+ * possibly one for the broadcast.
+ */
if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE;
goto out_err;
}
ipmb_addr = (struct ipmi_ipmb_addr *) addr;
if (ipmb_addr->lun > 3) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1491,29 +1562,31 @@ static int i_ipmi_request(ipmi_user_t user,
memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
if (recv_msg->msg.netfn & 0x1) {
- /* It's a response, so use the user's sequence
- from msgid. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ /*
+ * It's a response, so use the user's sequence
+ * from msgid.
+ */
+ ipmi_inc_stat(intf, sent_ipmb_responses);
format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
msgid, broadcast,
source_address, source_lun);
- /* Save the receive message so we can use it
- to deliver the response. */
+ /*
+ * Save the receive message so we can use it
+ * to deliver the response.
+ */
smi_msg->user_data = recv_msg;
} else {
/* It's a command, so get a sequence for it. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- spin_lock(&intf->counter_lock);
- intf->sent_ipmb_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, sent_ipmb_commands);
- /* Create a sequence number with a 1 second
- timeout and 4 retries. */
+ /*
+ * Create a sequence number with a 1 second
+ * timeout and 4 retries.
+ */
rv = intf_next_seq(intf,
recv_msg,
retry_time_ms,
@@ -1522,34 +1595,42 @@ static int i_ipmi_request(ipmi_user_t user,
&ipmb_seq,
&seqid);
if (rv) {
- /* We have used up all the sequence numbers,
- probably, so abort. */
+ /*
+ * We have used up all the sequence numbers,
+ * probably, so abort.
+ */
spin_unlock_irqrestore(&(intf->seq_lock),
flags);
goto out_err;
}
- /* Store the sequence number in the message,
- so that when the send message response
- comes back we can start the timer. */
+ /*
+ * Store the sequence number in the message,
+ * so that when the send message response
+ * comes back we can start the timer.
+ */
format_ipmb_msg(smi_msg, msg, ipmb_addr,
STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
ipmb_seq, broadcast,
source_address, source_lun);
- /* Copy the message into the recv message data, so we
- can retransmit it later if necessary. */
+ /*
+ * Copy the message into the recv message data, so we
+ * can retransmit it later if necessary.
+ */
memcpy(recv_msg->msg_data, smi_msg->data,
smi_msg->data_size);
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = smi_msg->data_size;
- /* We don't unlock until here, because we need
- to copy the completed message into the
- recv_msg before we release the lock.
- Otherwise, race conditions may bite us. I
- know that's pretty paranoid, but I prefer
- to be correct. */
+ /*
+ * We don't unlock until here, because we need
+ * to copy the completed message into the
+ * recv_msg before we release the lock.
+ * Otherwise, race conditions may bite us. I
+ * know that's pretty paranoid, but I prefer
+ * to be correct.
+ */
spin_unlock_irqrestore(&(intf->seq_lock), flags);
}
} else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
@@ -1558,21 +1639,16 @@ static int i_ipmi_request(ipmi_user_t user,
long seqid;
if (addr->channel >= IPMI_MAX_CHANNELS) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
if ((intf->channels[addr->channel].medium
- != IPMI_CHANNEL_MEDIUM_8023LAN)
+ != IPMI_CHANNEL_MEDIUM_8023LAN)
&& (intf->channels[addr->channel].medium
- != IPMI_CHANNEL_MEDIUM_ASYNC))
- {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ != IPMI_CHANNEL_MEDIUM_ASYNC)) {
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1585,18 +1661,14 @@ static int i_ipmi_request(ipmi_user_t user,
/* 11 for the header and 1 for the checksum. */
if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE;
goto out_err;
}
lan_addr = (struct ipmi_lan_addr *) addr;
if (lan_addr->lun > 3) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1604,28 +1676,30 @@ static int i_ipmi_request(ipmi_user_t user,
memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
if (recv_msg->msg.netfn & 0x1) {
- /* It's a response, so use the user's sequence
- from msgid. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ /*
+ * It's a response, so use the user's sequence
+ * from msgid.
+ */
+ ipmi_inc_stat(intf, sent_lan_responses);
format_lan_msg(smi_msg, msg, lan_addr, msgid,
msgid, source_lun);
- /* Save the receive message so we can use it
- to deliver the response. */
+ /*
+ * Save the receive message so we can use it
+ * to deliver the response.
+ */
smi_msg->user_data = recv_msg;
} else {
/* It's a command, so get a sequence for it. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- spin_lock(&intf->counter_lock);
- intf->sent_lan_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, sent_lan_commands);
- /* Create a sequence number with a 1 second
- timeout and 4 retries. */
+ /*
+ * Create a sequence number with a 1 second
+ * timeout and 4 retries.
+ */
rv = intf_next_seq(intf,
recv_msg,
retry_time_ms,
@@ -1634,40 +1708,46 @@ static int i_ipmi_request(ipmi_user_t user,
&ipmb_seq,
&seqid);
if (rv) {
- /* We have used up all the sequence numbers,
- probably, so abort. */
+ /*
+ * We have used up all the sequence numbers,
+ * probably, so abort.
+ */
spin_unlock_irqrestore(&(intf->seq_lock),
flags);
goto out_err;
}
- /* Store the sequence number in the message,
- so that when the send message response
- comes back we can start the timer. */
+ /*
+ * Store the sequence number in the message,
+ * so that when the send message response
+ * comes back we can start the timer.
+ */
format_lan_msg(smi_msg, msg, lan_addr,
STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
ipmb_seq, source_lun);
- /* Copy the message into the recv message data, so we
- can retransmit it later if necessary. */
+ /*
+ * Copy the message into the recv message data, so we
+ * can retransmit it later if necessary.
+ */
memcpy(recv_msg->msg_data, smi_msg->data,
smi_msg->data_size);
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = smi_msg->data_size;
- /* We don't unlock until here, because we need
- to copy the completed message into the
- recv_msg before we release the lock.
- Otherwise, race conditions may bite us. I
- know that's pretty paranoid, but I prefer
- to be correct. */
+ /*
+ * We don't unlock until here, because we need
+ * to copy the completed message into the
+ * recv_msg before we release the lock.
+ * Otherwise, race conditions may bite us. I
+ * know that's pretty paranoid, but I prefer
+ * to be correct.
+ */
spin_unlock_irqrestore(&(intf->seq_lock), flags);
}
} else {
/* Unknown address type. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1735,6 +1815,7 @@ int ipmi_request_settime(ipmi_user_t user,
retries,
retry_time_ms);
}
+EXPORT_SYMBOL(ipmi_request_settime);
int ipmi_request_supply_msgs(ipmi_user_t user,
struct ipmi_addr *addr,
@@ -1766,6 +1847,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
lun,
-1, 0);
}
+EXPORT_SYMBOL(ipmi_request_supply_msgs);
#ifdef CONFIG_PROC_FS
static int ipmb_file_read_proc(char *page, char **start, off_t off,
@@ -1790,7 +1872,7 @@ static int version_file_read_proc(char *page, char **start, off_t off,
char *out = (char *) page;
ipmi_smi_t intf = data;
- return sprintf(out, "%d.%d\n",
+ return sprintf(out, "%u.%u\n",
ipmi_version_major(&intf->bmc->id),
ipmi_version_minor(&intf->bmc->id));
}
@@ -1801,65 +1883,65 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
char *out = (char *) page;
ipmi_smi_t intf = data;
- out += sprintf(out, "sent_invalid_commands: %d\n",
- intf->sent_invalid_commands);
- out += sprintf(out, "sent_local_commands: %d\n",
- intf->sent_local_commands);
- out += sprintf(out, "handled_local_responses: %d\n",
- intf->handled_local_responses);
- out += sprintf(out, "unhandled_local_responses: %d\n",
- intf->unhandled_local_responses);
- out += sprintf(out, "sent_ipmb_commands: %d\n",
- intf->sent_ipmb_commands);
- out += sprintf(out, "sent_ipmb_command_errs: %d\n",
- intf->sent_ipmb_command_errs);
- out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
- intf->retransmitted_ipmb_commands);
- out += sprintf(out, "timed_out_ipmb_commands: %d\n",
- intf->timed_out_ipmb_commands);
- out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
- intf->timed_out_ipmb_broadcasts);
- out += sprintf(out, "sent_ipmb_responses: %d\n",
- intf->sent_ipmb_responses);
- out += sprintf(out, "handled_ipmb_responses: %d\n",
- intf->handled_ipmb_responses);
- out += sprintf(out, "invalid_ipmb_responses: %d\n",
- intf->invalid_ipmb_responses);
- out += sprintf(out, "unhandled_ipmb_responses: %d\n",
- intf->unhandled_ipmb_responses);
- out += sprintf(out, "sent_lan_commands: %d\n",
- intf->sent_lan_commands);
- out += sprintf(out, "sent_lan_command_errs: %d\n",
- intf->sent_lan_command_errs);
- out += sprintf(out, "retransmitted_lan_commands: %d\n",
- intf->retransmitted_lan_commands);
- out += sprintf(out, "timed_out_lan_commands: %d\n",
- intf->timed_out_lan_commands);
- out += sprintf(out, "sent_lan_responses: %d\n",
- intf->sent_lan_responses);
- out += sprintf(out, "handled_lan_responses: %d\n",
- intf->handled_lan_responses);
- out += sprintf(out, "invalid_lan_responses: %d\n",
- intf->invalid_lan_responses);
- out += sprintf(out, "unhandled_lan_responses: %d\n",
- intf->unhandled_lan_responses);
- out += sprintf(out, "handled_commands: %d\n",
- intf->handled_commands);
- out += sprintf(out, "invalid_commands: %d\n",
- intf->invalid_commands);
- out += sprintf(out, "unhandled_commands: %d\n",
- intf->unhandled_commands);
- out += sprintf(out, "invalid_events: %d\n",
- intf->invalid_events);
- out += sprintf(out, "events: %d\n",
- intf->events);
+ out += sprintf(out, "sent_invalid_commands: %u\n",
+ ipmi_get_stat(intf, sent_invalid_commands));
+ out += sprintf(out, "sent_local_commands: %u\n",
+ ipmi_get_stat(intf, sent_local_commands));
+ out += sprintf(out, "handled_local_responses: %u\n",
+ ipmi_get_stat(intf, handled_local_responses));
+ out += sprintf(out, "unhandled_local_responses: %u\n",
+ ipmi_get_stat(intf, unhandled_local_responses));
+ out += sprintf(out, "sent_ipmb_commands: %u\n",
+ ipmi_get_stat(intf, sent_ipmb_commands));
+ out += sprintf(out, "sent_ipmb_command_errs: %u\n",
+ ipmi_get_stat(intf, sent_ipmb_command_errs));
+ out += sprintf(out, "retransmitted_ipmb_commands: %u\n",
+ ipmi_get_stat(intf, retransmitted_ipmb_commands));
+ out += sprintf(out, "timed_out_ipmb_commands: %u\n",
+ ipmi_get_stat(intf, timed_out_ipmb_commands));
+ out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n",
+ ipmi_get_stat(intf, timed_out_ipmb_broadcasts));
+ out += sprintf(out, "sent_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, sent_ipmb_responses));
+ out += sprintf(out, "handled_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, handled_ipmb_responses));
+ out += sprintf(out, "invalid_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, invalid_ipmb_responses));
+ out += sprintf(out, "unhandled_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, unhandled_ipmb_responses));
+ out += sprintf(out, "sent_lan_commands: %u\n",
+ ipmi_get_stat(intf, sent_lan_commands));
+ out += sprintf(out, "sent_lan_command_errs: %u\n",
+ ipmi_get_stat(intf, sent_lan_command_errs));
+ out += sprintf(out, "retransmitted_lan_commands: %u\n",
+ ipmi_get_stat(intf, retransmitted_lan_commands));
+ out += sprintf(out, "timed_out_lan_commands: %u\n",
+ ipmi_get_stat(intf, timed_out_lan_commands));
+ out += sprintf(out, "sent_lan_responses: %u\n",
+ ipmi_get_stat(intf, sent_lan_responses));
+ out += sprintf(out, "handled_lan_responses: %u\n",
+ ipmi_get_stat(intf, handled_lan_responses));
+ out += sprintf(out, "invalid_lan_responses: %u\n",
+ ipmi_get_stat(intf, invalid_lan_responses));
+ out += sprintf(out, "unhandled_lan_responses: %u\n",
+ ipmi_get_stat(intf, unhandled_lan_responses));
+ out += sprintf(out, "handled_commands: %u\n",
+ ipmi_get_stat(intf, handled_commands));
+ out += sprintf(out, "invalid_commands: %u\n",
+ ipmi_get_stat(intf, invalid_commands));
+ out += sprintf(out, "unhandled_commands: %u\n",
+ ipmi_get_stat(intf, unhandled_commands));
+ out += sprintf(out, "invalid_events: %u\n",
+ ipmi_get_stat(intf, invalid_events));
+ out += sprintf(out, "events: %u\n",
+ ipmi_get_stat(intf, events));
return (out - ((char *) page));
}
#endif /* CONFIG_PROC_FS */
int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
- read_proc_t *read_proc, write_proc_t *write_proc,
+ read_proc_t *read_proc,
void *data, struct module *owner)
{
int rv = 0;
@@ -1886,7 +1968,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
} else {
file->data = data;
file->read_proc = read_proc;
- file->write_proc = write_proc;
file->owner = owner;
mutex_lock(&smi->proc_entry_lock);
@@ -1899,6 +1980,7 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
return rv;
}
+EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
static int add_proc_entries(ipmi_smi_t smi, int num)
{
@@ -1909,23 +1991,22 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
if (!smi->proc_dir)
rv = -ENOMEM;
- else {
+ else
smi->proc_dir->owner = THIS_MODULE;
- }
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "stats",
- stat_file_read_proc, NULL,
+ stat_file_read_proc,
smi, THIS_MODULE);
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "ipmb",
- ipmb_file_read_proc, NULL,
+ ipmb_file_read_proc,
smi, THIS_MODULE);
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "version",
- version_file_read_proc, NULL,
+ version_file_read_proc,
smi, THIS_MODULE);
#endif /* CONFIG_PROC_FS */
@@ -2210,37 +2291,47 @@ static int create_files(struct bmc_device *bmc)
err = device_create_file(&bmc->dev->dev,
&bmc->device_id_attr);
- if (err) goto out;
+ if (err)
+ goto out;
err = device_create_file(&bmc->dev->dev,
&bmc->provides_dev_sdrs_attr);
- if (err) goto out_devid;
+ if (err)
+ goto out_devid;
err = device_create_file(&bmc->dev->dev,
&bmc->revision_attr);
- if (err) goto out_sdrs;
+ if (err)
+ goto out_sdrs;
err = device_create_file(&bmc->dev->dev,
&bmc->firmware_rev_attr);
- if (err) goto out_rev;
+ if (err)
+ goto out_rev;
err = device_create_file(&bmc->dev->dev,
&bmc->version_attr);
- if (err) goto out_firm;
+ if (err)
+ goto out_firm;
err = device_create_file(&bmc->dev->dev,
&bmc->add_dev_support_attr);
- if (err) goto out_version;
+ if (err)
+ goto out_version;
err = device_create_file(&bmc->dev->dev,
&bmc->manufacturer_id_attr);
- if (err) goto out_add_dev;
+ if (err)
+ goto out_add_dev;
err = device_create_file(&bmc->dev->dev,
&bmc->product_id_attr);
- if (err) goto out_manu;
+ if (err)
+ goto out_manu;
if (bmc->id.aux_firmware_revision_set) {
err = device_create_file(&bmc->dev->dev,
&bmc->aux_firmware_rev_attr);
- if (err) goto out_prod_id;
+ if (err)
+ goto out_prod_id;
}
if (bmc->guid_set) {
err = device_create_file(&bmc->dev->dev,
&bmc->guid_attr);
- if (err) goto out_aux_firm;
+ if (err)
+ goto out_aux_firm;
}
return 0;
@@ -2368,8 +2459,10 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
"ipmi_msghandler:"
" Unable to register bmc device: %d\n",
rv);
- /* Don't go to out_err, you can only do that if
- the device is registered already. */
+ /*
+ * Don't go to out_err, you can only do that if
+ * the device is registered already.
+ */
return rv;
}
@@ -2560,17 +2653,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
&& (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
- && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
- {
+ && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) {
/* It's the one we want */
if (msg->msg.data[0] != 0) {
/* Got an error from the channel, just go on. */
if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
- /* If the MC does not support this
- command, that is legal. We just
- assume it has one IPMB at channel
- zero. */
+ /*
+ * If the MC does not support this
+ * command, that is legal. We just
+ * assume it has one IPMB at channel
+ * zero.
+ */
intf->channels[0].medium
= IPMI_CHANNEL_MEDIUM_IPMB;
intf->channels[0].protocol
@@ -2591,7 +2685,7 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
- next_channel:
+ next_channel:
intf->curr_channel++;
if (intf->curr_channel >= IPMI_MAX_CHANNELS)
wake_up(&intf->waitq);
@@ -2619,6 +2713,7 @@ void ipmi_poll_interface(ipmi_user_t user)
if (intf->handlers->poll)
intf->handlers->poll(intf->send_info);
}
+EXPORT_SYMBOL(ipmi_poll_interface);
int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
void *send_info,
@@ -2633,14 +2728,18 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
ipmi_smi_t tintf;
struct list_head *link;
- /* Make sure the driver is actually initialized, this handles
- problems with initialization order. */
+ /*
+ * Make sure the driver is actually initialized, this handles
+ * problems with initialization order.
+ */
if (!initialized) {
rv = ipmi_init_msghandler();
if (rv)
return rv;
- /* The init code doesn't return an error if it was turned
- off, but it won't initialize. Check that. */
+ /*
+ * The init code doesn't return an error if it was turned
+ * off, but it won't initialize. Check that.
+ */
if (!initialized)
return -ENODEV;
}
@@ -2688,8 +2787,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
spin_lock_init(&intf->maintenance_mode_lock);
INIT_LIST_HEAD(&intf->cmd_rcvrs);
init_waitqueue_head(&intf->waitq);
+ for (i = 0; i < IPMI_NUM_STATS; i++)
+ atomic_set(&intf->stats[i], 0);
- spin_lock_init(&intf->counter_lock);
intf->proc_dir = NULL;
mutex_lock(&smi_watchers_mutex);
@@ -2717,11 +2817,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
get_guid(intf);
if ((intf->ipmi_version_major > 1)
- || ((intf->ipmi_version_major == 1)
- && (intf->ipmi_version_minor >= 5)))
- {
- /* Start scanning the channels to see what is
- available. */
+ || ((intf->ipmi_version_major == 1)
+ && (intf->ipmi_version_minor >= 5))) {
+ /*
+ * Start scanning the channels to see what is
+ * available.
+ */
intf->null_user_handler = channel_handler;
intf->curr_channel = 0;
rv = send_channel_info_cmd(intf, 0);
@@ -2769,6 +2870,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
return rv;
}
+EXPORT_SYMBOL(ipmi_register_smi);
static void cleanup_smi_msgs(ipmi_smi_t intf)
{
@@ -2803,8 +2905,10 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
remove_proc_entries(intf);
- /* Call all the watcher interfaces to tell them that
- an interface is gone. */
+ /*
+ * Call all the watcher interfaces to tell them that
+ * an interface is gone.
+ */
list_for_each_entry(w, &smi_watchers, link)
w->smi_gone(intf_num);
mutex_unlock(&smi_watchers_mutex);
@@ -2812,22 +2916,21 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
kref_put(&intf->refcount, intf_free);
return 0;
}
+EXPORT_SYMBOL(ipmi_unregister_smi);
static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
struct ipmi_ipmb_addr ipmb_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
-
- /* This is 11, not 10, because the response must contain a
- * completion code. */
+ /*
+ * This is 11, not 10, because the response must contain a
+ * completion code.
+ */
if (msg->rsp_size < 11) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_ipmb_responses);
return 0;
}
@@ -2841,37 +2944,38 @@ static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
ipmb_addr.channel = msg->rsp[3] & 0x0f;
ipmb_addr.lun = msg->rsp[7] & 3;
- /* It's a response from a remote entity. Look up the sequence
- number and handle the response. */
+ /*
+ * It's a response from a remote entity. Look up the sequence
+ * number and handle the response.
+ */
if (intf_find_seq(intf,
msg->rsp[7] >> 2,
msg->rsp[3] & 0x0f,
msg->rsp[8],
(msg->rsp[4] >> 2) & (~1),
(struct ipmi_addr *) &(ipmb_addr),
- &recv_msg))
- {
- /* We were unable to find the sequence number,
- so just nuke the message. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ &recv_msg)) {
+ /*
+ * We were unable to find the sequence number,
+ * so just nuke the message.
+ */
+ ipmi_inc_stat(intf, unhandled_ipmb_responses);
return 0;
}
memcpy(recv_msg->msg_data,
&(msg->rsp[9]),
msg->rsp_size - 9);
- /* THe other fields matched, so no need to set them, except
- for netfn, which needs to be the response that was
- returned, not the request value. */
+ /*
+ * The other fields matched, so no need to set them, except
+ * for netfn, which needs to be the response that was
+ * returned, not the request value.
+ */
recv_msg->msg.netfn = msg->rsp[4] >> 2;
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = msg->rsp_size - 10;
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_ipmb_responses);
deliver_response(recv_msg);
return 0;
@@ -2888,14 +2992,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
ipmi_user_t user = NULL;
struct ipmi_ipmb_addr *ipmb_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
struct ipmi_smi_handlers *handlers;
if (msg->rsp_size < 10) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_commands);
return 0;
}
@@ -2919,19 +3020,17 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
if (user == NULL) {
/* We didn't find a user, deliver an error response. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, unhandled_commands);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg->data[1] = IPMI_SEND_MSG_CMD;
msg->data[2] = msg->rsp[3];
msg->data[3] = msg->rsp[6];
- msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
+ msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
- /* rqseq/lun */
- msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
+ /* rqseq/lun */
+ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
msg->data[8] = msg->rsp[8]; /* cmd */
msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
@@ -2950,23 +3049,25 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
handlers = intf->handlers;
if (handlers) {
handlers->sender(intf->send_info, msg, 0);
- /* We used the message, so return the value
- that causes it to not be freed or
- queued. */
+ /*
+ * We used the message, so return the value
+ * that causes it to not be freed or
+ * queued.
+ */
rv = -1;
}
rcu_read_unlock();
} else {
/* Deliver the message to the user. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_commands);
recv_msg = ipmi_alloc_recv_msg();
if (!recv_msg) {
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+ * later.
+ */
rv = 1;
kref_put(&user->refcount, free_user);
} else {
@@ -2977,8 +3078,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
ipmb_addr->lun = msg->rsp[7] & 3;
ipmb_addr->channel = msg->rsp[3] & 0xf;
- /* Extract the rest of the message information
- from the IPMB header.*/
+ /*
+ * Extract the rest of the message information
+ * from the IPMB header.
+ */
recv_msg->user = user;
recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
recv_msg->msgid = msg->rsp[7] >> 2;
@@ -2986,8 +3089,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
recv_msg->msg.cmd = msg->rsp[8];
recv_msg->msg.data = recv_msg->msg_data;
- /* We chop off 10, not 9 bytes because the checksum
- at the end also needs to be removed. */
+ /*
+ * We chop off 10, not 9 bytes because the checksum
+ * at the end also needs to be removed.
+ */
recv_msg->msg.data_len = msg->rsp_size - 10;
memcpy(recv_msg->msg_data,
&(msg->rsp[9]),
@@ -3004,16 +3109,15 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
{
struct ipmi_lan_addr lan_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
- /* This is 13, not 12, because the response must contain a
- * completion code. */
+ /*
+ * This is 13, not 12, because the response must contain a
+ * completion code.
+ */
if (msg->rsp_size < 13) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_lan_responses);
return 0;
}
@@ -3030,37 +3134,38 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf,
lan_addr.privilege = msg->rsp[3] >> 4;
lan_addr.lun = msg->rsp[9] & 3;
- /* It's a response from a remote entity. Look up the sequence
- number and handle the response. */
+ /*
+ * It's a response from a remote entity. Look up the sequence
+ * number and handle the response.
+ */
if (intf_find_seq(intf,
msg->rsp[9] >> 2,
msg->rsp[3] & 0x0f,
msg->rsp[10],
(msg->rsp[6] >> 2) & (~1),
(struct ipmi_addr *) &(lan_addr),
- &recv_msg))
- {
- /* We were unable to find the sequence number,
- so just nuke the message. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ &recv_msg)) {
+ /*
+ * We were unable to find the sequence number,
+ * so just nuke the message.
+ */
+ ipmi_inc_stat(intf, unhandled_lan_responses);
return 0;
}
memcpy(recv_msg->msg_data,
&(msg->rsp[11]),
msg->rsp_size - 11);
- /* The other fields matched, so no need to set them, except
- for netfn, which needs to be the response that was
- returned, not the request value. */
+ /*
+ * The other fields matched, so no need to set them, except
+ * for netfn, which needs to be the response that was
+ * returned, not the request value.
+ */
recv_msg->msg.netfn = msg->rsp[6] >> 2;
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = msg->rsp_size - 12;
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_lan_responses);
deliver_response(recv_msg);
return 0;
@@ -3077,13 +3182,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
ipmi_user_t user = NULL;
struct ipmi_lan_addr *lan_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
if (msg->rsp_size < 12) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_commands);
return 0;
}
@@ -3107,23 +3209,23 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
if (user == NULL) {
/* We didn't find a user, just give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, unhandled_commands);
- rv = 0; /* Don't do anything with these messages, just
- allow them to be freed. */
+ /*
+ * Don't do anything with these messages, just allow
+ * them to be freed.
+ */
+ rv = 0;
} else {
/* Deliver the message to the user. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_commands);
recv_msg = ipmi_alloc_recv_msg();
if (!recv_msg) {
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling later.
+ */
rv = 1;
kref_put(&user->refcount, free_user);
} else {
@@ -3137,8 +3239,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
lan_addr->channel = msg->rsp[3] & 0xf;
lan_addr->privilege = msg->rsp[3] >> 4;
- /* Extract the rest of the message information
- from the IPMB header.*/
+ /*
+ * Extract the rest of the message information
+ * from the IPMB header.
+ */
recv_msg->user = user;
recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
recv_msg->msgid = msg->rsp[9] >> 2;
@@ -3146,8 +3250,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
recv_msg->msg.cmd = msg->rsp[10];
recv_msg->msg.data = recv_msg->msg_data;
- /* We chop off 12, not 11 bytes because the checksum
- at the end also needs to be removed. */
+ /*
+ * We chop off 12, not 11 bytes because the checksum
+ * at the end also needs to be removed.
+ */
recv_msg->msg.data_len = msg->rsp_size - 12;
memcpy(recv_msg->msg_data,
&(msg->rsp[11]),
@@ -3163,7 +3269,7 @@ static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
struct ipmi_smi_msg *msg)
{
struct ipmi_system_interface_addr *smi_addr;
-
+
recv_msg->msgid = 0;
smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
@@ -3189,9 +3295,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf,
if (msg->rsp_size < 19) {
/* Message is too small to be an IPMB event. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_events++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_events);
return 0;
}
@@ -3204,12 +3308,12 @@ static int handle_read_event_rsp(ipmi_smi_t intf,
spin_lock_irqsave(&intf->events_lock, flags);
- spin_lock(&intf->counter_lock);
- intf->events++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, events);
- /* Allocate and fill in one message for every user that is getting
- events. */
+ /*
+ * Allocate and fill in one message for every user that is
+ * getting events.
+ */
rcu_read_lock();
list_for_each_entry_rcu(user, &intf->users, link) {
if (!user->gets_events)
@@ -3223,9 +3327,11 @@ static int handle_read_event_rsp(ipmi_smi_t intf,
list_del(&recv_msg->link);
ipmi_free_recv_msg(recv_msg);
}
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+ * later.
+ */
rv = 1;
goto out;
}
@@ -3246,13 +3352,17 @@ static int handle_read_event_rsp(ipmi_smi_t intf,
deliver_response(recv_msg);
}
} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
- /* No one to receive the message, put it in queue if there's
- not already too many things in the queue. */
+ /*
+ * No one to receive the message, put it in queue if there's
+ * not already too many things in the queue.
+ */
recv_msg = ipmi_alloc_recv_msg();
if (!recv_msg) {
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+ * later.
+ */
rv = 1;
goto out;
}
@@ -3260,11 +3370,14 @@ static int handle_read_event_rsp(ipmi_smi_t intf,
copy_event_into_recv_msg(recv_msg, msg);
list_add_tail(&(recv_msg->link), &(intf->waiting_events));
intf->waiting_events_count++;
- } else {
- /* There's too many things in the queue, discard this
- message. */
- printk(KERN_WARNING PFX "Event queue full, discarding an"
- " incoming event\n");
+ } else if (!intf->event_msg_printed) {
+ /*
+ * There's too many things in the queue, discard this
+ * message.
+ */
+ printk(KERN_WARNING PFX "Event queue full, discarding"
+ " incoming events\n");
+ intf->event_msg_printed = 1;
}
out:
@@ -3277,16 +3390,15 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
struct ipmi_user *user;
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
- if (recv_msg == NULL)
- {
- printk(KERN_WARNING"IPMI message received with no owner. This\n"
- "could be because of a malformed message, or\n"
- "because of a hardware error. Contact your\n"
- "hardware vender for assistance\n");
+ if (recv_msg == NULL) {
+ printk(KERN_WARNING
+ "IPMI message received with no owner. This\n"
+ "could be because of a malformed message, or\n"
+ "because of a hardware error. Contact your\n"
+ "hardware vender for assistance\n");
return 0;
}
@@ -3294,16 +3406,12 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
/* Make sure the user still exists. */
if (user && !user->valid) {
/* The user for the message went away, so give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, unhandled_local_responses);
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_local_responses);
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
recv_msg->msgid = msg->msgid;
smi_addr = ((struct ipmi_system_interface_addr *)
@@ -3324,9 +3432,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf,
return 0;
}
-/* Handle a new message. Return 1 if the message should be requeued,
- 0 if the message should be freed, or -1 if the message should not
- be freed or requeued. */
+/*
+ * Handle a new message. Return 1 if the message should be requeued,
+ * 0 if the message should be freed, or -1 if the message should not
+ * be freed or requeued.
+ */
static int handle_new_recv_msg(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
@@ -3351,10 +3461,12 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
msg->rsp[1] = msg->data[1];
msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
msg->rsp_size = 3;
- } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
- || (msg->rsp[1] != msg->data[1])) /* Command */
- {
- /* The response is not even marginally correct. */
+ } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))
+ || (msg->rsp[1] != msg->data[1])) {
+ /*
+ * The NetFN and Command in the response is not even
+ * marginally correct.
+ */
printk(KERN_WARNING PFX "BMC returned incorrect response,"
" expected netfn %x cmd %x, got netfn %x cmd %x\n",
(msg->data[0] >> 2) | 1, msg->data[1],
@@ -3369,10 +3481,11 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
&& (msg->rsp[1] == IPMI_SEND_MSG_CMD)
- && (msg->user_data != NULL))
- {
- /* It's a response to a response we sent. For this we
- deliver a send message response to the user. */
+ && (msg->user_data != NULL)) {
+ /*
+ * It's a response to a response we sent. For this we
+ * deliver a send message response to the user.
+ */
struct ipmi_recv_msg *recv_msg = msg->user_data;
requeue = 0;
@@ -3398,8 +3511,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
recv_msg->msg_data[0] = msg->rsp[2];
deliver_response(recv_msg);
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
- && (msg->rsp[1] == IPMI_GET_MSG_CMD))
- {
+ && (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
/* It's from the receive queue. */
chan = msg->rsp[3] & 0xf;
if (chan >= IPMI_MAX_CHANNELS) {
@@ -3411,12 +3523,16 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
switch (intf->channels[chan].medium) {
case IPMI_CHANNEL_MEDIUM_IPMB:
if (msg->rsp[4] & 0x04) {
- /* It's a response, so find the
- requesting message and send it up. */
+ /*
+ * It's a response, so find the
+ * requesting message and send it up.
+ */
requeue = handle_ipmb_get_msg_rsp(intf, msg);
} else {
- /* It's a command to the SMS from some other
- entity. Handle that. */
+ /*
+ * It's a command to the SMS from some other
+ * entity. Handle that.
+ */
requeue = handle_ipmb_get_msg_cmd(intf, msg);
}
break;
@@ -3424,25 +3540,30 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
case IPMI_CHANNEL_MEDIUM_8023LAN:
case IPMI_CHANNEL_MEDIUM_ASYNC:
if (msg->rsp[6] & 0x04) {
- /* It's a response, so find the
- requesting message and send it up. */
+ /*
+ * It's a response, so find the
+ * requesting message and send it up.
+ */
requeue = handle_lan_get_msg_rsp(intf, msg);
} else {
- /* It's a command to the SMS from some other
- entity. Handle that. */
+ /*
+ * It's a command to the SMS from some other
+ * entity. Handle that.
+ */
requeue = handle_lan_get_msg_cmd(intf, msg);
}
break;
default:
- /* We don't handle the channel type, so just
- * free the message. */
+ /*
+ * We don't handle the channel type, so just
+ * free the message.
+ */
requeue = 0;
}
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
- && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
- {
+ && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
/* It's an asyncronous event. */
requeue = handle_read_event_rsp(intf, msg);
} else {
@@ -3458,71 +3579,82 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
void ipmi_smi_msg_received(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
- unsigned long flags;
+ unsigned long flags = 0; /* keep us warning-free. */
int rv;
+ int run_to_completion;
if ((msg->data_size >= 2)
&& (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
- && (msg->user_data == NULL))
- {
- /* This is the local response to a command send, start
- the timer for these. The user_data will not be
- NULL if this is a response send, and we will let
- response sends just go through. */
-
- /* Check for errors, if we get certain errors (ones
- that mean basically we can try again later), we
- ignore them and start the timer. Otherwise we
- report the error immediately. */
+ && (msg->user_data == NULL)) {
+ /*
+ * This is the local response to a command send, start
+ * the timer for these. The user_data will not be
+ * NULL if this is a response send, and we will let
+ * response sends just go through.
+ */
+
+ /*
+ * Check for errors, if we get certain errors (ones
+ * that mean basically we can try again later), we
+ * ignore them and start the timer. Otherwise we
+ * report the error immediately.
+ */
if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
&& (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
&& (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
&& (msg->rsp[2] != IPMI_BUS_ERR)
- && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
- {
+ && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) {
int chan = msg->rsp[3] & 0xf;
/* Got an error sending the message, handle it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
if (chan >= IPMI_MAX_CHANNELS)
; /* This shouldn't happen */
else if ((intf->channels[chan].medium
== IPMI_CHANNEL_MEDIUM_8023LAN)
|| (intf->channels[chan].medium
== IPMI_CHANNEL_MEDIUM_ASYNC))
- intf->sent_lan_command_errs++;
+ ipmi_inc_stat(intf, sent_lan_command_errs);
else
- intf->sent_ipmb_command_errs++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_ipmb_command_errs);
intf_err_seq(intf, msg->msgid, msg->rsp[2]);
- } else {
+ } else
/* The message was sent, start the timer. */
intf_start_seq_timer(intf, msg->msgid);
- }
ipmi_free_smi_msg(msg);
goto out;
}
- /* To preserve message order, if the list is not empty, we
- tack this message onto the end of the list. */
- spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+ /*
+ * To preserve message order, if the list is not empty, we
+ * tack this message onto the end of the list.
+ */
+ run_to_completion = intf->run_to_completion;
+ if (!run_to_completion)
+ spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
if (!list_empty(&intf->waiting_msgs)) {
list_add_tail(&msg->link, &intf->waiting_msgs);
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
goto out;
}
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
-
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+
rv = handle_new_recv_msg(intf, msg);
if (rv > 0) {
- /* Could not handle the message now, just add it to a
- list to handle later. */
- spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+ /*
+ * Could not handle the message now, just add it to a
+ * list to handle later.
+ */
+ run_to_completion = intf->run_to_completion;
+ if (!run_to_completion)
+ spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
list_add_tail(&msg->link, &intf->waiting_msgs);
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
} else if (rv == 0) {
ipmi_free_smi_msg(msg);
}
@@ -3530,6 +3662,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
out:
return;
}
+EXPORT_SYMBOL(ipmi_smi_msg_received);
void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
{
@@ -3544,7 +3677,7 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
}
rcu_read_unlock();
}
-
+EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
static struct ipmi_smi_msg *
smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
@@ -3552,14 +3685,16 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
{
struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
if (!smi_msg)
- /* If we can't allocate the message, then just return, we
- get 4 retries, so this should be ok. */
+ /*
+ * If we can't allocate the message, then just return, we
+ * get 4 retries, so this should be ok.
+ */
return NULL;
memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
smi_msg->data_size = recv_msg->msg.data_len;
smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
-
+
#ifdef DEBUG_MSGING
{
int m;
@@ -3594,28 +3729,26 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
ent->inuse = 0;
msg = ent->recv_msg;
list_add_tail(&msg->link, timeouts);
- spin_lock(&intf->counter_lock);
if (ent->broadcast)
- intf->timed_out_ipmb_broadcasts++;
+ ipmi_inc_stat(intf, timed_out_ipmb_broadcasts);
else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
- intf->timed_out_lan_commands++;
+ ipmi_inc_stat(intf, timed_out_lan_commands);
else
- intf->timed_out_ipmb_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, timed_out_ipmb_commands);
} else {
struct ipmi_smi_msg *smi_msg;
/* More retries, send again. */
- /* Start with the max timer, set to normal
- timer after the message is sent. */
+ /*
+ * Start with the max timer, set to normal timer after
+ * the message is sent.
+ */
ent->timeout = MAX_MSG_TIMEOUT;
ent->retries_left--;
- spin_lock(&intf->counter_lock);
if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
- intf->retransmitted_lan_commands++;
+ ipmi_inc_stat(intf, retransmitted_lan_commands);
else
- intf->retransmitted_ipmb_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, retransmitted_ipmb_commands);
smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
ent->seqid);
@@ -3624,11 +3757,13 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
spin_unlock_irqrestore(&intf->seq_lock, *flags);
- /* Send the new message. We send with a zero
- * priority. It timed out, I doubt time is
- * that critical now, and high priority
- * messages are really only for messages to the
- * local MC, which don't get resent. */
+ /*
+ * Send the new message. We send with a zero
+ * priority. It timed out, I doubt time is that
+ * critical now, and high priority messages are really
+ * only for messages to the local MC, which don't get
+ * resent.
+ */
handlers = intf->handlers;
if (handlers)
intf->handlers->sender(intf->send_info,
@@ -3659,16 +3794,20 @@ static void ipmi_timeout_handler(long timeout_period)
list_del(&smi_msg->link);
ipmi_free_smi_msg(smi_msg);
} else {
- /* To preserve message order, quit if we
- can't handle a message. */
+ /*
+ * To preserve message order, quit if we
+ * can't handle a message.
+ */
break;
}
}
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
- /* Go through the seq table and find any messages that
- have timed out, putting them in the timeouts
- list. */
+ /*
+ * Go through the seq table and find any messages that
+ * have timed out, putting them in the timeouts
+ * list.
+ */
INIT_LIST_HEAD(&timeouts);
spin_lock_irqsave(&intf->seq_lock, flags);
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
@@ -3694,8 +3833,7 @@ static void ipmi_timeout_handler(long timeout_period)
intf->auto_maintenance_timeout
-= timeout_period;
if (!intf->maintenance_mode
- && (intf->auto_maintenance_timeout <= 0))
- {
+ && (intf->auto_maintenance_timeout <= 0)) {
intf->maintenance_mode_enable = 0;
maintenance_mode_update(intf);
}
@@ -3713,8 +3851,10 @@ static void ipmi_request_event(void)
struct ipmi_smi_handlers *handlers;
rcu_read_lock();
- /* Called from the timer, no need to check if handlers is
- * valid. */
+ /*
+ * Called from the timer, no need to check if handlers is
+ * valid.
+ */
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
/* No event requests when in maintenance mode. */
if (intf->maintenance_mode_enable)
@@ -3735,10 +3875,12 @@ static struct timer_list ipmi_timer;
/* How many jiffies does it take to get to the timeout time. */
#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
-/* Request events from the queue every second (this is the number of
- IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
- future, IPMI will add a way to know immediately if an event is in
- the queue and this silliness can go away. */
+/*
+ * Request events from the queue every second (this is the number of
+ * IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
+ * future, IPMI will add a way to know immediately if an event is in
+ * the queue and this silliness can go away.
+ */
#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
static atomic_t stop_operation;
@@ -3782,6 +3924,7 @@ struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
}
return rv;
}
+EXPORT_SYMBOL(ipmi_alloc_smi_msg);
static void free_recv_msg(struct ipmi_recv_msg *msg)
{
@@ -3789,7 +3932,7 @@ static void free_recv_msg(struct ipmi_recv_msg *msg)
kfree(msg);
}
-struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
{
struct ipmi_recv_msg *rv;
@@ -3808,6 +3951,7 @@ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
kref_put(&msg->user->refcount, free_user);
msg->done(msg);
}
+EXPORT_SYMBOL(ipmi_free_recv_msg);
#ifdef CONFIG_IPMI_PANIC_EVENT
@@ -3825,8 +3969,7 @@ static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
&& (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
&& (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
- && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
- {
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) {
/* A get event receiver command, save it. */
intf->event_receiver = msg->msg.data[1];
intf->event_receiver_lun = msg->msg.data[2] & 0x3;
@@ -3838,10 +3981,11 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
&& (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
&& (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
- && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
- {
- /* A get device id command, save if we are an event
- receiver or generator. */
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) {
+ /*
+ * A get device id command, save if we are an event
+ * receiver or generator.
+ */
intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
}
@@ -3874,8 +4018,10 @@ static void send_panic_events(char *str)
data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
- /* Put a few breadcrumbs in. Hopefully later we can add more things
- to make the panic events more useful. */
+ /*
+ * Put a few breadcrumbs in. Hopefully later we can add more things
+ * to make the panic events more useful.
+ */
if (str) {
data[3] = str[0];
data[6] = str[1];
@@ -3891,6 +4037,7 @@ static void send_panic_events(char *str)
/* Interface is not ready. */
continue;
+ intf->run_to_completion = 1;
/* Send the event announcing the panic. */
intf->handlers->set_run_to_completion(intf->send_info, 1);
i_ipmi_request(NULL,
@@ -3908,9 +4055,11 @@ static void send_panic_events(char *str)
}
#ifdef CONFIG_IPMI_PANIC_STRING
- /* On every interface, dump a bunch of OEM event holding the
- string. */
- if (!str)
+ /*
+ * On every interface, dump a bunch of OEM event holding the
+ * string.
+ */
+ if (!str)
return;
/* For every registered interface, send the event. */
@@ -3931,11 +4080,13 @@ static void send_panic_events(char *str)
*/
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
- find the SEL to put them in and stick them in
- there. */
+ /*
+ * 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
+ * find the SEL to put them in and stick them in
+ * there.
+ */
/* Get capabilities from the get device id. */
intf->local_sel_device = 0;
@@ -3983,24 +4134,29 @@ static void send_panic_events(char *str)
}
intf->null_user_handler = NULL;
- /* Validate the event receiver. The low bit must not
- be 1 (it must be a valid IPMB address), it cannot
- be zero, and it must not be my address. */
- if (((intf->event_receiver & 1) == 0)
+ /*
+ * Validate the event receiver. The low bit must not
+ * be 1 (it must be a valid IPMB address), it cannot
+ * be zero, and it must not be my address.
+ */
+ if (((intf->event_receiver & 1) == 0)
&& (intf->event_receiver != 0)
- && (intf->event_receiver != intf->channels[0].address))
- {
- /* The event receiver is valid, send an IPMB
- message. */
+ && (intf->event_receiver != intf->channels[0].address)) {
+ /*
+ * The event receiver is valid, send an IPMB
+ * message.
+ */
ipmb = (struct ipmi_ipmb_addr *) &addr;
ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
ipmb->channel = 0; /* FIXME - is this right? */
ipmb->lun = intf->event_receiver_lun;
ipmb->slave_addr = intf->event_receiver;
} else if (intf->local_sel_device) {
- /* The event receiver was not valid (or was
- me), but I am an SEL device, just dump it
- in my SEL. */
+ /*
+ * The event receiver was not valid (or was
+ * me), but I am an SEL device, just dump it
+ * in my SEL.
+ */
si = (struct ipmi_system_interface_addr *) &addr;
si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
si->channel = IPMI_BMC_CHANNEL;
@@ -4008,7 +4164,6 @@ static void send_panic_events(char *str)
} else
continue; /* No where to send the event. */
-
msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
msg.data = data;
@@ -4025,8 +4180,10 @@ static void send_panic_events(char *str)
data[2] = 0xf0; /* OEM event without timestamp. */
data[3] = intf->channels[0].address;
data[4] = j++; /* sequence # */
- /* Always give 11 bytes, so strncpy will fill
- it with zeroes for me. */
+ /*
+ * Always give 11 bytes, so strncpy will fill
+ * it with zeroes for me.
+ */
strncpy(data+5, p, 11);
p += size;
@@ -4043,7 +4200,7 @@ static void send_panic_events(char *str)
intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
- }
+ }
#endif /* CONFIG_IPMI_PANIC_STRING */
}
#endif /* CONFIG_IPMI_PANIC_EVENT */
@@ -4052,7 +4209,7 @@ static int has_panicked;
static int panic_event(struct notifier_block *this,
unsigned long event,
- void *ptr)
+ void *ptr)
{
ipmi_smi_t intf;
@@ -4066,6 +4223,7 @@ static int panic_event(struct notifier_block *this,
/* Interface is not ready. */
continue;
+ intf->run_to_completion = 1;
intf->handlers->set_run_to_completion(intf->send_info, 1);
}
@@ -4133,11 +4291,16 @@ static __exit void cleanup_ipmi(void)
atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
- /* This can't be called if any interfaces exist, so no worry about
- shutting down the interfaces. */
+ /*
+ * This can't be called if any interfaces exist, so no worry
+ * about shutting down the interfaces.
+ */
- /* Tell the timer to stop, then wait for it to stop. This avoids
- problems with race conditions removing the timer here. */
+ /*
+ * Tell the timer to stop, then wait for it to stop. This
+ * avoids problems with race conditions removing the timer
+ * here.
+ */
atomic_inc(&stop_operation);
del_timer_sync(&ipmi_timer);
@@ -4164,31 +4327,6 @@ module_exit(cleanup_ipmi);
module_init(ipmi_init_msghandler_mod);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
-MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
+MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI"
+ " interface.");
MODULE_VERSION(IPMI_DRIVER_VERSION);
-
-EXPORT_SYMBOL(ipmi_create_user);
-EXPORT_SYMBOL(ipmi_destroy_user);
-EXPORT_SYMBOL(ipmi_get_version);
-EXPORT_SYMBOL(ipmi_request_settime);
-EXPORT_SYMBOL(ipmi_request_supply_msgs);
-EXPORT_SYMBOL(ipmi_poll_interface);
-EXPORT_SYMBOL(ipmi_register_smi);
-EXPORT_SYMBOL(ipmi_unregister_smi);
-EXPORT_SYMBOL(ipmi_register_for_cmd);
-EXPORT_SYMBOL(ipmi_unregister_for_cmd);
-EXPORT_SYMBOL(ipmi_smi_msg_received);
-EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
-EXPORT_SYMBOL(ipmi_alloc_smi_msg);
-EXPORT_SYMBOL(ipmi_addr_length);
-EXPORT_SYMBOL(ipmi_validate_addr);
-EXPORT_SYMBOL(ipmi_set_gets_events);
-EXPORT_SYMBOL(ipmi_smi_watcher_register);
-EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
-EXPORT_SYMBOL(ipmi_set_my_address);
-EXPORT_SYMBOL(ipmi_get_my_address);
-EXPORT_SYMBOL(ipmi_set_my_LUN);
-EXPORT_SYMBOL(ipmi_get_my_LUN);
-EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
-EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
-EXPORT_SYMBOL(ipmi_free_recv_msg);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index b86186de7f07..a261bd735dfb 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -87,7 +87,10 @@ MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
/* parameter definition to allow user to flag power cycle */
module_param(poweroff_powercycle, int, 0644);
-MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+MODULE_PARM_DESC(poweroff_powercycle,
+ " Set to non-zero to enable power cycle instead of power"
+ " down. Power cycle is contingent on hardware support,"
+ " otherwise it defaults back to power down.");
/* Stuff from the get device id command. */
static unsigned int mfg_id;
@@ -95,22 +98,25 @@ static unsigned int prod_id;
static unsigned char capabilities;
static unsigned char ipmi_version;
-/* We use our own messages for this operation, we don't let the system
- allocate them, since we may be in a panic situation. The whole
- thing is single-threaded, anyway, so multiple messages are not
- required. */
+/*
+ * We use our own messages for this operation, we don't let the system
+ * allocate them, since we may be in a panic situation. The whole
+ * thing is single-threaded, anyway, so multiple messages are not
+ * required.
+ */
+static atomic_t dummy_count = ATOMIC_INIT(0);
static void dummy_smi_free(struct ipmi_smi_msg *msg)
{
+ atomic_dec(&dummy_count);
}
static void dummy_recv_free(struct ipmi_recv_msg *msg)
{
+ atomic_dec(&dummy_count);
}
-static struct ipmi_smi_msg halt_smi_msg =
-{
+static struct ipmi_smi_msg halt_smi_msg = {
.done = dummy_smi_free
};
-static struct ipmi_recv_msg halt_recv_msg =
-{
+static struct ipmi_recv_msg halt_recv_msg = {
.done = dummy_recv_free
};
@@ -127,8 +133,7 @@ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
complete(comp);
}
-static struct ipmi_user_hndl ipmi_poweroff_handler =
-{
+static struct ipmi_user_hndl ipmi_poweroff_handler = {
.ipmi_recv_hndl = receive_handler
};
@@ -152,17 +157,28 @@ static int ipmi_request_wait_for_response(ipmi_user_t user,
return halt_recv_msg.msg.data[0];
}
-/* We are in run-to-completion mode, no completion is desired. */
+/* Wait for message to complete, spinning. */
static int ipmi_request_in_rc_mode(ipmi_user_t user,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg)
{
int rv;
+ atomic_set(&dummy_count, 2);
rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
&halt_smi_msg, &halt_recv_msg, 0);
- if (rv)
+ if (rv) {
+ atomic_set(&dummy_count, 0);
return rv;
+ }
+
+ /*
+ * Spin until our message is done.
+ */
+ while (atomic_read(&dummy_count) > 0) {
+ ipmi_poll_interface(user);
+ cpu_relax();
+ }
return halt_recv_msg.msg.data[0];
}
@@ -184,47 +200,47 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user,
static void (*atca_oem_poweroff_hook)(ipmi_user_t user);
-static void pps_poweroff_atca (ipmi_user_t user)
+static void pps_poweroff_atca(ipmi_user_t user)
{
- struct ipmi_system_interface_addr smi_addr;
- struct kernel_ipmi_msg send_msg;
- int rv;
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
-
- printk(KERN_INFO PFX "PPS powerdown hook used");
-
- send_msg.netfn = IPMI_NETFN_OEM;
- send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
- send_msg.data = IPMI_ATCA_PPS_IANA;
- send_msg.data_len = 3;
- rv = ipmi_request_in_rc_mode(user,
- (struct ipmi_addr *) &smi_addr,
- &send_msg);
- if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
- printk(KERN_ERR PFX "Unable to send ATCA ,"
- " IPMI error 0x%x\n", rv);
- }
+ struct ipmi_system_interface_addr smi_addr;
+ struct kernel_ipmi_msg send_msg;
+ int rv;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
+
+ printk(KERN_INFO PFX "PPS powerdown hook used");
+
+ send_msg.netfn = IPMI_NETFN_OEM;
+ send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
+ send_msg.data = IPMI_ATCA_PPS_IANA;
+ send_msg.data_len = 3;
+ rv = ipmi_request_in_rc_mode(user,
+ (struct ipmi_addr *) &smi_addr,
+ &send_msg);
+ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
+ printk(KERN_ERR PFX "Unable to send ATCA ,"
+ " IPMI error 0x%x\n", rv);
+ }
return;
}
-static int ipmi_atca_detect (ipmi_user_t user)
+static int ipmi_atca_detect(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
int rv;
unsigned char data[1];
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
/*
* Use get address info to check and see if we are ATCA
@@ -238,28 +254,30 @@ static int ipmi_atca_detect (ipmi_user_t user)
(struct ipmi_addr *) &smi_addr,
&send_msg);
- printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id);
- if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
- && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
- printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n");
+ printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n",
+ mfg_id, prod_id);
+ if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
+ && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
+ printk(KERN_INFO PFX
+ "Installing Pigeon Point Systems Poweroff Hook\n");
atca_oem_poweroff_hook = pps_poweroff_atca;
}
return !rv;
}
-static void ipmi_poweroff_atca (ipmi_user_t user)
+static void ipmi_poweroff_atca(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
int rv;
unsigned char data[4];
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
printk(KERN_INFO PFX "Powering down via ATCA power command\n");
@@ -273,23 +291,24 @@ static void ipmi_poweroff_atca (ipmi_user_t user)
data[2] = 0; /* Power Level */
data[3] = 0; /* Don't change saved presets */
send_msg.data = data;
- send_msg.data_len = sizeof (data);
+ send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
- /** At this point, the system may be shutting down, and most
- ** serial drivers (if used) will have interrupts turned off
- ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE
- ** return code
- **/
- if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
+ /*
+ * At this point, the system may be shutting down, and most
+ * serial drivers (if used) will have interrupts turned off
+ * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE
+ * return code
+ */
+ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
printk(KERN_ERR PFX "Unable to send ATCA powerdown message,"
" IPMI error 0x%x\n", rv);
goto out;
}
- if(atca_oem_poweroff_hook)
- return atca_oem_poweroff_hook(user);
+ if (atca_oem_poweroff_hook)
+ atca_oem_poweroff_hook(user);
out:
return;
}
@@ -310,13 +329,13 @@ static void ipmi_poweroff_atca (ipmi_user_t user)
#define IPMI_CPI1_PRODUCT_ID 0x000157
#define IPMI_CPI1_MANUFACTURER_ID 0x0108
-static int ipmi_cpi1_detect (ipmi_user_t user)
+static int ipmi_cpi1_detect(ipmi_user_t user)
{
return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
&& (prod_id == IPMI_CPI1_PRODUCT_ID));
}
-static void ipmi_poweroff_cpi1 (ipmi_user_t user)
+static void ipmi_poweroff_cpi1(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct ipmi_ipmb_addr ipmb_addr;
@@ -328,12 +347,12 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user)
unsigned char aer_addr;
unsigned char aer_lun;
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
@@ -425,7 +444,7 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user)
*/
#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
-static int ipmi_dell_chassis_detect (ipmi_user_t user)
+static int ipmi_dell_chassis_detect(ipmi_user_t user)
{
const char ipmi_version_major = ipmi_version & 0xF;
const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
@@ -444,25 +463,25 @@ static int ipmi_dell_chassis_detect (ipmi_user_t user)
#define IPMI_NETFN_CHASSIS_REQUEST 0
#define IPMI_CHASSIS_CONTROL_CMD 0x02
-static int ipmi_chassis_detect (ipmi_user_t user)
+static int ipmi_chassis_detect(ipmi_user_t user)
{
/* Chassis support, use it. */
return (capabilities & 0x80);
}
-static void ipmi_poweroff_chassis (ipmi_user_t user)
+static void ipmi_poweroff_chassis(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
int rv;
unsigned char data[1];
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
powercyclefailed:
printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
@@ -525,15 +544,13 @@ static struct poweroff_function poweroff_functions[] = {
/* Called on a powerdown request. */
-static void ipmi_poweroff_function (void)
+static void ipmi_poweroff_function(void)
{
if (!ready)
return;
/* Use run-to-completion mode, since interrupts may be off. */
- ipmi_user_set_run_to_completion(ipmi_user, 1);
specific_poweroff_func(ipmi_user);
- ipmi_user_set_run_to_completion(ipmi_user, 0);
}
/* Wait for an IPMI interface to be installed, the first one installed
@@ -561,13 +578,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
ipmi_ifnum = if_num;
- /*
- * Do a get device ide and store some results, since this is
+ /*
+ * Do a get device ide and store some results, since this is
* used by several functions.
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
send_msg.netfn = IPMI_NETFN_APP_REQUEST;
send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
@@ -632,8 +649,7 @@ static void ipmi_po_smi_gone(int if_num)
pm_power_off = old_poweroff_func;
}
-static struct ipmi_smi_watcher smi_watcher =
-{
+static struct ipmi_smi_watcher smi_watcher = {
.owner = THIS_MODULE,
.new_smi = ipmi_po_new_smi,
.smi_gone = ipmi_po_smi_gone
@@ -675,12 +691,12 @@ static struct ctl_table_header *ipmi_table_header;
/*
* Startup and shutdown functions.
*/
-static int ipmi_poweroff_init (void)
+static int ipmi_poweroff_init(void)
{
int rv;
- printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot.\n");
+ printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -"
+ " IPMI Powerdown via sys_reboot.\n");
if (poweroff_powercycle)
printk(KERN_INFO PFX "Power cycle is enabled.\n");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 4f560d0bb808..192688344ed2 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -80,7 +80,7 @@
#define SI_USEC_PER_JIFFY (1000000/HZ)
#define SI_TIMEOUT_JIFFIES (SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY)
#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
- short timeout */
+ short timeout */
/* Bit for BMC global enables. */
#define IPMI_BMC_RCV_MSG_INTR 0x01
@@ -114,14 +114,61 @@ static char *si_to_str[] = { "kcs", "smic", "bt" };
#define DEVICE_NAME "ipmi_si"
-static struct device_driver ipmi_driver =
-{
+static struct device_driver ipmi_driver = {
.name = DEVICE_NAME,
.bus = &platform_bus_type
};
-struct smi_info
-{
+
+/*
+ * Indexes into stats[] in smi_info below.
+ */
+enum si_stat_indexes {
+ /*
+ * Number of times the driver requested a timer while an operation
+ * was in progress.
+ */
+ SI_STAT_short_timeouts = 0,
+
+ /*
+ * Number of times the driver requested a timer while nothing was in
+ * progress.
+ */
+ SI_STAT_long_timeouts,
+
+ /* Number of times the interface was idle while being polled. */
+ SI_STAT_idles,
+
+ /* Number of interrupts the driver handled. */
+ SI_STAT_interrupts,
+
+ /* Number of time the driver got an ATTN from the hardware. */
+ SI_STAT_attentions,
+
+ /* Number of times the driver requested flags from the hardware. */
+ SI_STAT_flag_fetches,
+
+ /* Number of times the hardware didn't follow the state machine. */
+ SI_STAT_hosed_count,
+
+ /* Number of completed messages. */
+ SI_STAT_complete_transactions,
+
+ /* Number of IPMI events received from the hardware. */
+ SI_STAT_events,
+
+ /* Number of watchdog pretimeouts. */
+ SI_STAT_watchdog_pretimeouts,
+
+ /* Number of asyncronous messages received. */
+ SI_STAT_incoming_messages,
+
+
+ /* This *must* remain last, add new values above this. */
+ SI_NUM_STATS
+};
+
+struct smi_info {
int intf_num;
ipmi_smi_t intf;
struct si_sm_data *si_sm;
@@ -134,8 +181,10 @@ struct smi_info
struct ipmi_smi_msg *curr_msg;
enum si_intf_state si_state;
- /* Used to handle the various types of I/O that can occur with
- IPMI */
+ /*
+ * Used to handle the various types of I/O that can occur with
+ * IPMI
+ */
struct si_sm_io io;
int (*io_setup)(struct smi_info *info);
void (*io_cleanup)(struct smi_info *info);
@@ -146,15 +195,18 @@ struct smi_info
void (*addr_source_cleanup)(struct smi_info *info);
void *addr_source_data;
- /* Per-OEM handler, called from handle_flags().
- Returns 1 when handle_flags() needs to be re-run
- or 0 indicating it set si_state itself.
- */
+ /*
+ * Per-OEM handler, called from handle_flags(). Returns 1
+ * when handle_flags() needs to be re-run or 0 indicating it
+ * set si_state itself.
+ */
int (*oem_data_avail_handler)(struct smi_info *smi_info);
- /* Flags from the last GET_MSG_FLAGS command, used when an ATTN
- is set to hold the flags until we are done handling everything
- from the flags. */
+ /*
+ * Flags from the last GET_MSG_FLAGS command, used when an ATTN
+ * is set to hold the flags until we are done handling everything
+ * from the flags.
+ */
#define RECEIVE_MSG_AVAIL 0x01
#define EVENT_MSG_BUFFER_FULL 0x02
#define WDT_PRE_TIMEOUT_INT 0x08
@@ -162,25 +214,31 @@ struct smi_info
#define OEM1_DATA_AVAIL 0x40
#define OEM2_DATA_AVAIL 0x80
#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \
- OEM1_DATA_AVAIL | \
- OEM2_DATA_AVAIL)
+ OEM1_DATA_AVAIL | \
+ OEM2_DATA_AVAIL)
unsigned char msg_flags;
- /* If set to true, this will request events the next time the
- state machine is idle. */
+ /*
+ * If set to true, this will request events the next time the
+ * state machine is idle.
+ */
atomic_t req_events;
- /* If true, run the state machine to completion on every send
- call. Generally used after a panic to make sure stuff goes
- out. */
+ /*
+ * If true, run the state machine to completion on every send
+ * call. Generally used after a panic to make sure stuff goes
+ * out.
+ */
int run_to_completion;
/* The I/O port of an SI interface. */
int port;
- /* The space between start addresses of the two ports. For
- instance, if the first port is 0xca2 and the spacing is 4, then
- the second port is 0xca6. */
+ /*
+ * The space between start addresses of the two ports. For
+ * instance, if the first port is 0xca2 and the spacing is 4, then
+ * the second port is 0xca6.
+ */
unsigned int spacing;
/* zero if no irq; */
@@ -195,10 +253,12 @@ struct smi_info
/* Used to gracefully stop the timer without race conditions. */
atomic_t stop_operation;
- /* The driver will disable interrupts when it gets into a
- situation where it cannot handle messages due to lack of
- memory. Once that situation clears up, it will re-enable
- interrupts. */
+ /*
+ * The driver will disable interrupts when it gets into a
+ * situation where it cannot handle messages due to lack of
+ * memory. Once that situation clears up, it will re-enable
+ * interrupts.
+ */
int interrupt_disabled;
/* From the get device id response... */
@@ -208,33 +268,28 @@ struct smi_info
struct device *dev;
struct platform_device *pdev;
- /* True if we allocated the device, false if it came from
- * someplace else (like PCI). */
+ /*
+ * True if we allocated the device, false if it came from
+ * someplace else (like PCI).
+ */
int dev_registered;
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
/* Counters and things for the proc filesystem. */
- spinlock_t count_lock;
- unsigned long short_timeouts;
- unsigned long long_timeouts;
- unsigned long timeout_restarts;
- unsigned long idles;
- unsigned long interrupts;
- unsigned long attentions;
- unsigned long flag_fetches;
- unsigned long hosed_count;
- unsigned long complete_transactions;
- unsigned long events;
- unsigned long watchdog_pretimeouts;
- unsigned long incoming_messages;
-
- struct task_struct *thread;
+ atomic_t stats[SI_NUM_STATS];
+
+ struct task_struct *thread;
struct list_head link;
};
+#define smi_inc_stat(smi, stat) \
+ atomic_inc(&(smi)->stats[SI_STAT_ ## stat])
+#define smi_get_stat(smi, stat) \
+ ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat]))
+
#define SI_MAX_PARMS 4
static int force_kipmid[SI_MAX_PARMS];
@@ -246,7 +301,7 @@ static int try_smi_init(struct smi_info *smi);
static void cleanup_one_si(struct smi_info *to_clean);
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
-static int register_xaction_notifier(struct notifier_block * nb)
+static int register_xaction_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&xaction_notifier_list, nb);
}
@@ -255,7 +310,7 @@ static void deliver_recv_msg(struct smi_info *smi_info,
struct ipmi_smi_msg *msg)
{
/* Deliver the message to the upper layer with the lock
- released. */
+ released. */
spin_unlock(&(smi_info->si_lock));
ipmi_smi_msg_received(smi_info->intf, msg);
spin_lock(&(smi_info->si_lock));
@@ -287,9 +342,12 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
struct timeval t;
#endif
- /* No need to save flags, we aleady have interrupts off and we
- already hold the SMI lock. */
- spin_lock(&(smi_info->msg_lock));
+ /*
+ * No need to save flags, we aleady have interrupts off and we
+ * already hold the SMI lock.
+ */
+ if (!smi_info->run_to_completion)
+ spin_lock(&(smi_info->msg_lock));
/* Pick the high priority queue first. */
if (!list_empty(&(smi_info->hp_xmit_msgs))) {
@@ -310,7 +368,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
link);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
- printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
err = atomic_notifier_call_chain(&xaction_notifier_list,
0, smi_info);
@@ -322,14 +380,14 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
smi_info->si_sm,
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
- if (err) {
+ if (err)
return_hosed_msg(smi_info, err);
- }
rv = SI_SM_CALL_WITHOUT_DELAY;
}
- out:
- spin_unlock(&(smi_info->msg_lock));
+ out:
+ if (!smi_info->run_to_completion)
+ spin_unlock(&(smi_info->msg_lock));
return rv;
}
@@ -338,8 +396,10 @@ static void start_enable_irq(struct smi_info *smi_info)
{
unsigned char msg[2];
- /* If we are enabling interrupts, we have to tell the
- BMC to use them. */
+ /*
+ * If we are enabling interrupts, we have to tell the
+ * BMC to use them.
+ */
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
@@ -371,10 +431,12 @@ static void start_clear_flags(struct smi_info *smi_info)
smi_info->si_state = SI_CLEARING_FLAGS;
}
-/* When we have a situtaion where we run out of memory and cannot
- allocate messages, we just leave them in the BMC and run the system
- polled until we can allocate some memory. Once we have some
- memory, we will re-enable the interrupt. */
+/*
+ * When we have a situtaion where we run out of memory and cannot
+ * allocate messages, we just leave them in the BMC and run the system
+ * polled until we can allocate some memory. Once we have some
+ * memory, we will re-enable the interrupt.
+ */
static inline void disable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
@@ -396,9 +458,7 @@ static void handle_flags(struct smi_info *smi_info)
retry:
if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
/* Watchdog pre-timeout */
- spin_lock(&smi_info->count_lock);
- smi_info->watchdog_pretimeouts++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, watchdog_pretimeouts);
start_clear_flags(smi_info);
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
@@ -444,12 +504,11 @@ static void handle_flags(struct smi_info *smi_info)
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
- smi_info->oem_data_avail_handler) {
+ smi_info->oem_data_avail_handler) {
if (smi_info->oem_data_avail_handler(smi_info))
goto retry;
- } else {
+ } else
smi_info->si_state = SI_NORMAL;
- }
}
static void handle_transaction_done(struct smi_info *smi_info)
@@ -459,7 +518,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
struct timeval t;
do_gettimeofday(&t);
- printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
switch (smi_info->si_state) {
case SI_NORMAL:
@@ -472,9 +531,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->curr_msg->rsp,
IPMI_MAX_MSG_LENGTH);
- /* Do this here becase deliver_recv_msg() releases the
- lock, and a new message can be put in during the
- time the lock is released. */
+ /*
+ * Do this here becase deliver_recv_msg() releases the
+ * lock, and a new message can be put in during the
+ * time the lock is released.
+ */
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
deliver_recv_msg(smi_info, msg);
@@ -488,12 +549,13 @@ static void handle_transaction_done(struct smi_info *smi_info)
/* We got the flags from the SMI, now handle them. */
len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
if (msg[2] != 0) {
- /* Error fetching flags, just give up for
- now. */
+ /* Error fetching flags, just give up for now. */
smi_info->si_state = SI_NORMAL;
} else if (len < 4) {
- /* Hmm, no flags. That's technically illegal, but
- don't use uninitialized data. */
+ /*
+ * Hmm, no flags. That's technically illegal, but
+ * don't use uninitialized data.
+ */
smi_info->si_state = SI_NORMAL;
} else {
smi_info->msg_flags = msg[3];
@@ -530,9 +592,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->curr_msg->rsp,
IPMI_MAX_MSG_LENGTH);
- /* Do this here becase deliver_recv_msg() releases the
- lock, and a new message can be put in during the
- time the lock is released. */
+ /*
+ * Do this here becase deliver_recv_msg() releases the
+ * lock, and a new message can be put in during the
+ * time the lock is released.
+ */
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
if (msg->rsp[2] != 0) {
@@ -543,14 +607,14 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
handle_flags(smi_info);
} else {
- spin_lock(&smi_info->count_lock);
- smi_info->events++;
- spin_unlock(&smi_info->count_lock);
-
- /* Do this before we deliver the message
- because delivering the message releases the
- lock and something else can mess with the
- state. */
+ smi_inc_stat(smi_info, events);
+
+ /*
+ * Do this before we deliver the message
+ * because delivering the message releases the
+ * lock and something else can mess with the
+ * state.
+ */
handle_flags(smi_info);
deliver_recv_msg(smi_info, msg);
@@ -566,9 +630,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->curr_msg->rsp,
IPMI_MAX_MSG_LENGTH);
- /* Do this here becase deliver_recv_msg() releases the
- lock, and a new message can be put in during the
- time the lock is released. */
+ /*
+ * Do this here becase deliver_recv_msg() releases the
+ * lock, and a new message can be put in during the
+ * time the lock is released.
+ */
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
if (msg->rsp[2] != 0) {
@@ -579,14 +645,14 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
handle_flags(smi_info);
} else {
- spin_lock(&smi_info->count_lock);
- smi_info->incoming_messages++;
- spin_unlock(&smi_info->count_lock);
-
- /* Do this before we deliver the message
- because delivering the message releases the
- lock and something else can mess with the
- state. */
+ smi_inc_stat(smi_info, incoming_messages);
+
+ /*
+ * Do this before we deliver the message
+ * because delivering the message releases the
+ * lock and something else can mess with the
+ * state.
+ */
handle_flags(smi_info);
deliver_recv_msg(smi_info, msg);
@@ -674,69 +740,70 @@ static void handle_transaction_done(struct smi_info *smi_info)
}
}
-/* Called on timeouts and events. Timeouts should pass the elapsed
- time, interrupts should pass in zero. Must be called with
- si_lock held and interrupts disabled. */
+/*
+ * Called on timeouts and events. Timeouts should pass the elapsed
+ * time, interrupts should pass in zero. Must be called with
+ * si_lock held and interrupts disabled.
+ */
static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
int time)
{
enum si_sm_result si_sm_result;
restart:
- /* There used to be a loop here that waited a little while
- (around 25us) before giving up. That turned out to be
- pointless, the minimum delays I was seeing were in the 300us
- range, which is far too long to wait in an interrupt. So
- we just run until the state machine tells us something
- happened or it needs a delay. */
+ /*
+ * There used to be a loop here that waited a little while
+ * (around 25us) before giving up. That turned out to be
+ * pointless, the minimum delays I was seeing were in the 300us
+ * range, which is far too long to wait in an interrupt. So
+ * we just run until the state machine tells us something
+ * happened or it needs a delay.
+ */
si_sm_result = smi_info->handlers->event(smi_info->si_sm, time);
time = 0;
while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY)
- {
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
- }
- if (si_sm_result == SI_SM_TRANSACTION_COMPLETE)
- {
- spin_lock(&smi_info->count_lock);
- smi_info->complete_transactions++;
- spin_unlock(&smi_info->count_lock);
+ if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) {
+ smi_inc_stat(smi_info, complete_transactions);
handle_transaction_done(smi_info);
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
- }
- else if (si_sm_result == SI_SM_HOSED)
- {
- spin_lock(&smi_info->count_lock);
- smi_info->hosed_count++;
- spin_unlock(&smi_info->count_lock);
+ } else if (si_sm_result == SI_SM_HOSED) {
+ smi_inc_stat(smi_info, hosed_count);
- /* Do the before return_hosed_msg, because that
- releases the lock. */
+ /*
+ * Do the before return_hosed_msg, because that
+ * releases the lock.
+ */
smi_info->si_state = SI_NORMAL;
if (smi_info->curr_msg != NULL) {
- /* If we were handling a user message, format
- a response to send to the upper layer to
- tell it about the error. */
+ /*
+ * If we were handling a user message, format
+ * a response to send to the upper layer to
+ * tell it about the error.
+ */
return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED);
}
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
}
- /* We prefer handling attn over new messages. */
- if (si_sm_result == SI_SM_ATTN)
- {
+ /*
+ * We prefer handling attn over new messages. But don't do
+ * this if there is not yet an upper layer to handle anything.
+ */
+ if (likely(smi_info->intf) && si_sm_result == SI_SM_ATTN) {
unsigned char msg[2];
- spin_lock(&smi_info->count_lock);
- smi_info->attentions++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, attentions);
- /* Got a attn, send down a get message flags to see
- what's causing it. It would be better to handle
- this in the upper layer, but due to the way
- interrupts work with the SMI, that's not really
- possible. */
+ /*
+ * Got a attn, send down a get message flags to see
+ * what's causing it. It would be better to handle
+ * this in the upper layer, but due to the way
+ * interrupts work with the SMI, that's not really
+ * possible.
+ */
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_MSG_FLAGS_CMD;
@@ -748,20 +815,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
/* If we are currently idle, try to start the next message. */
if (si_sm_result == SI_SM_IDLE) {
- spin_lock(&smi_info->count_lock);
- smi_info->idles++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, idles);
si_sm_result = start_next_msg(smi_info);
if (si_sm_result != SI_SM_IDLE)
goto restart;
- }
+ }
if ((si_sm_result == SI_SM_IDLE)
- && (atomic_read(&smi_info->req_events)))
- {
- /* We are idle and the upper layer requested that I fetch
- events, so do so. */
+ && (atomic_read(&smi_info->req_events))) {
+ /*
+ * We are idle and the upper layer requested that I fetch
+ * events, so do so.
+ */
atomic_set(&smi_info->req_events, 0);
smi_info->curr_msg = ipmi_alloc_smi_msg();
@@ -803,56 +869,50 @@ static void sender(void *send_info,
return;
}
- spin_lock_irqsave(&(smi_info->msg_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
if (smi_info->run_to_completion) {
- /* If we are running to completion, then throw it in
- the list and run transactions until everything is
- clear. Priority doesn't matter here. */
+ /*
+ * If we are running to completion, then throw it in
+ * the list and run transactions until everything is
+ * clear. Priority doesn't matter here.
+ */
+
+ /*
+ * Run to completion means we are single-threaded, no
+ * need for locks.
+ */
list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
- /* We have to release the msg lock and claim the smi
- lock in this case, because of race conditions. */
- spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
-
- spin_lock_irqsave(&(smi_info->si_lock), flags);
result = smi_event_handler(smi_info, 0);
while (result != SI_SM_IDLE) {
udelay(SI_SHORT_TIMEOUT_USEC);
result = smi_event_handler(smi_info,
SI_SHORT_TIMEOUT_USEC);
}
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return;
- } else {
- if (priority > 0) {
- list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));
- } else {
- list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
- }
}
- spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
- spin_lock_irqsave(&(smi_info->si_lock), flags);
- if ((smi_info->si_state == SI_NORMAL)
- && (smi_info->curr_msg == NULL))
- {
+ spin_lock_irqsave(&smi_info->msg_lock, flags);
+ if (priority > 0)
+ list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
+ else
+ list_add_tail(&msg->link, &smi_info->xmit_msgs);
+ spin_unlock_irqrestore(&smi_info->msg_lock, flags);
+
+ spin_lock_irqsave(&smi_info->si_lock, flags);
+ if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL)
start_next_msg(smi_info);
- }
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+ spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
static void set_run_to_completion(void *send_info, int i_run_to_completion)
{
struct smi_info *smi_info = send_info;
enum si_sm_result result;
- unsigned long flags;
-
- spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_info->run_to_completion = i_run_to_completion;
if (i_run_to_completion) {
@@ -863,8 +923,6 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion)
SI_SHORT_TIMEOUT_USEC);
}
}
-
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
}
static int ipmi_thread(void *data)
@@ -878,9 +936,8 @@ static int ipmi_thread(void *data)
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_result = smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
- if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
- /* do nothing */
- }
+ if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+ ; /* do nothing */
else if (smi_result == SI_SM_CALL_WITH_DELAY)
schedule();
else
@@ -931,7 +988,7 @@ static void smi_timeout(unsigned long data)
spin_lock_irqsave(&(smi_info->si_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
- printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
jiffies_now = jiffies;
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
@@ -945,23 +1002,19 @@ static void smi_timeout(unsigned long data)
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
/* Running with interrupts, only do long timeouts. */
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->long_timeouts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
+ smi_inc_stat(smi_info, long_timeouts);
goto do_add_timer;
}
- /* If the state machine asks for a short delay, then shorten
- the timer timeout. */
+ /*
+ * If the state machine asks for a short delay, then shorten
+ * the timer timeout.
+ */
if (smi_result == SI_SM_CALL_WITH_DELAY) {
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->short_timeouts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
+ smi_inc_stat(smi_info, short_timeouts);
smi_info->si_timer.expires = jiffies + 1;
} else {
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->long_timeouts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
+ smi_inc_stat(smi_info, long_timeouts);
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
}
@@ -979,13 +1032,11 @@ static irqreturn_t si_irq_handler(int irq, void *data)
spin_lock_irqsave(&(smi_info->si_lock), flags);
- spin_lock(&smi_info->count_lock);
- smi_info->interrupts++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, interrupts);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
- printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
@@ -1028,7 +1079,7 @@ static int smi_start_processing(void *send_info,
* The BT interface is efficient enough to not need a thread,
* and there is no need for a thread if we have interrupts.
*/
- else if ((new_smi->si_type != SI_BT) && (!new_smi->irq))
+ else if ((new_smi->si_type != SI_BT) && (!new_smi->irq))
enable = 1;
if (enable) {
@@ -1054,8 +1105,7 @@ static void set_maintenance_mode(void *send_info, int enable)
atomic_set(&smi_info->req_events, 0);
}
-static struct ipmi_smi_handlers handlers =
-{
+static struct ipmi_smi_handlers handlers = {
.owner = THIS_MODULE,
.start_processing = smi_start_processing,
.sender = sender,
@@ -1065,8 +1115,10 @@ static struct ipmi_smi_handlers handlers =
.poll = poll,
};
-/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
- a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */
+/*
+ * There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+ * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS.
+ */
static LIST_HEAD(smi_infos);
static DEFINE_MUTEX(smi_infos_lock);
@@ -1257,10 +1309,9 @@ static void port_cleanup(struct smi_info *info)
int idx;
if (addr) {
- for (idx = 0; idx < info->io_size; idx++) {
+ for (idx = 0; idx < info->io_size; idx++)
release_region(addr + idx * info->io.regspacing,
info->io.regsize);
- }
}
}
@@ -1274,8 +1325,10 @@ static int port_setup(struct smi_info *info)
info->io_cleanup = port_cleanup;
- /* Figure out the actual inb/inw/inl/etc routine to use based
- upon the register size. */
+ /*
+ * Figure out the actual inb/inw/inl/etc routine to use based
+ * upon the register size.
+ */
switch (info->io.regsize) {
case 1:
info->io.inputb = port_inb;
@@ -1290,17 +1343,18 @@ static int port_setup(struct smi_info *info)
info->io.outputb = port_outl;
break;
default:
- printk("ipmi_si: Invalid register size: %d\n",
+ printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
info->io.regsize);
return -EINVAL;
}
- /* Some BIOSes reserve disjoint I/O regions in their ACPI
+ /*
+ * Some BIOSes reserve disjoint I/O regions in their ACPI
* tables. This causes problems when trying to register the
* entire I/O region. Therefore we must register each I/O
* port separately.
*/
- for (idx = 0; idx < info->io_size; idx++) {
+ for (idx = 0; idx < info->io_size; idx++) {
if (request_region(addr + idx * info->io.regspacing,
info->io.regsize, DEVICE_NAME) == NULL) {
/* Undo allocations */
@@ -1388,8 +1442,10 @@ static int mem_setup(struct smi_info *info)
info->io_cleanup = mem_cleanup;
- /* Figure out the actual readb/readw/readl/etc routine to use based
- upon the register size. */
+ /*
+ * Figure out the actual readb/readw/readl/etc routine to use based
+ * upon the register size.
+ */
switch (info->io.regsize) {
case 1:
info->io.inputb = intf_mem_inb;
@@ -1410,16 +1466,18 @@ static int mem_setup(struct smi_info *info)
break;
#endif
default:
- printk("ipmi_si: Invalid register size: %d\n",
+ printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
info->io.regsize);
return -EINVAL;
}
- /* Calculate the total amount of memory to claim. This is an
+ /*
+ * Calculate the total amount of memory to claim. This is an
* unusual looking calculation, but it avoids claiming any
* more memory than it has to. It will claim everything
* between the first address to the end of the last full
- * register. */
+ * register.
+ */
mapsize = ((info->io_size * info->io.regspacing)
- (info->io.regspacing - info->io.regsize));
@@ -1749,9 +1807,11 @@ static __devinit void hardcode_find_bmc(void)
#include <linux/acpi.h>
-/* Once we get an ACPI failure, we don't try any more, because we go
- through the tables sequentially. Once we don't find a table, there
- are no more. */
+/*
+ * Once we get an ACPI failure, we don't try any more, because we go
+ * through the tables sequentially. Once we don't find a table, there
+ * are no more.
+ */
static int acpi_failure;
/* For GPE-type interrupts. */
@@ -1765,9 +1825,7 @@ static u32 ipmi_acpi_gpe(void *context)
spin_lock_irqsave(&(smi_info->si_lock), flags);
- spin_lock(&smi_info->count_lock);
- smi_info->interrupts++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, interrupts);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
@@ -1816,7 +1874,8 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
/*
* Defined at
- * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf
+ * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/
+ * Docs/TechPapers/IA64/hpspmi.pdf
*/
struct SPMITable {
s8 Signature[4];
@@ -1838,14 +1897,18 @@ struct SPMITable {
*/
u8 InterruptType;
- /* If bit 0 of InterruptType is set, then this is the SCI
- interrupt in the GPEx_STS register. */
+ /*
+ * If bit 0 of InterruptType is set, then this is the SCI
+ * interrupt in the GPEx_STS register.
+ */
u8 GPE;
s16 Reserved;
- /* If bit 1 of InterruptType is set, then this is the I/O
- APIC/SAPIC interrupt. */
+ /*
+ * If bit 1 of InterruptType is set, then this is the I/O
+ * APIC/SAPIC interrupt.
+ */
u32 GlobalSystemInterrupt;
/* The actual register address. */
@@ -1863,7 +1926,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
if (spmi->IPMIlegacy != 1) {
printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
- return -ENODEV;
+ return -ENODEV;
}
if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
@@ -1880,8 +1943,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
info->addr_source = "ACPI";
/* Figure out the interface type. */
- switch (spmi->InterfaceType)
- {
+ switch (spmi->InterfaceType) {
case 1: /* KCS */
info->si_type = SI_KCS;
break;
@@ -1929,7 +1991,8 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
info->io.addr_type = IPMI_IO_ADDR_SPACE;
} else {
kfree(info);
- printk("ipmi_si: Unknown ACPI I/O Address type\n");
+ printk(KERN_WARNING
+ "ipmi_si: Unknown ACPI I/O Address type\n");
return -EIO;
}
info->io.addr_data = spmi->addr.address;
@@ -1963,8 +2026,7 @@ static __devinit void acpi_find_bmc(void)
#endif
#ifdef CONFIG_DMI
-struct dmi_ipmi_data
-{
+struct dmi_ipmi_data {
u8 type;
u8 addr_space;
unsigned long base_addr;
@@ -1989,11 +2051,10 @@ static int __devinit decode_dmi(const struct dmi_header *dm,
/* I/O */
base_addr &= 0xFFFE;
dmi->addr_space = IPMI_IO_ADDR_SPACE;
- }
- else {
+ } else
/* Memory */
dmi->addr_space = IPMI_MEM_ADDR_SPACE;
- }
+
/* If bit 4 of byte 0x10 is set, then the lsb for the address
is odd. */
dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
@@ -2002,7 +2063,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm,
/* The top two bits of byte 0x10 hold the register spacing. */
reg_spacing = (data[0x10] & 0xC0) >> 6;
- switch(reg_spacing){
+ switch (reg_spacing) {
case 0x00: /* Byte boundaries */
dmi->offset = 1;
break;
@@ -2018,12 +2079,14 @@ static int __devinit decode_dmi(const struct dmi_header *dm,
}
} else {
/* Old DMI spec. */
- /* Note that technically, the lower bit of the base
+ /*
+ * Note that technically, the lower bit of the base
* address should be 1 if the address is I/O and 0 if
* the address is in memory. So many systems get that
* wrong (and all that I have seen are I/O) so we just
* ignore that bit and assume I/O. Systems that use
- * memory should use the newer spec, anyway. */
+ * memory should use the newer spec, anyway.
+ */
dmi->base_addr = base_addr & 0xfffe;
dmi->addr_space = IPMI_IO_ADDR_SPACE;
dmi->offset = 1;
@@ -2230,13 +2293,13 @@ static struct pci_device_id ipmi_pci_devices[] = {
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
static struct pci_driver ipmi_pci_driver = {
- .name = DEVICE_NAME,
- .id_table = ipmi_pci_devices,
- .probe = ipmi_pci_probe,
- .remove = __devexit_p(ipmi_pci_remove),
+ .name = DEVICE_NAME,
+ .id_table = ipmi_pci_devices,
+ .probe = ipmi_pci_probe,
+ .remove = __devexit_p(ipmi_pci_remove),
#ifdef CONFIG_PM
- .suspend = ipmi_pci_suspend,
- .resume = ipmi_pci_resume,
+ .suspend = ipmi_pci_suspend,
+ .resume = ipmi_pci_resume,
#endif
};
#endif /* CONFIG_PCI */
@@ -2289,10 +2352,16 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
info->si_type = (enum si_type) match->data;
info->addr_source = "device-tree";
- info->io_setup = mem_setup;
info->irq_setup = std_irq_setup;
- info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+ if (resource.flags & IORESOURCE_IO) {
+ info->io_setup = port_setup;
+ info->io.addr_type = IPMI_IO_ADDR_SPACE;
+ } else {
+ info->io_setup = mem_setup;
+ info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+ }
+
info->io.addr_data = resource.start;
info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE;
@@ -2306,7 +2375,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
info->io.addr_data, info->io.regsize, info->io.regspacing,
info->irq);
- dev->dev.driver_data = (void*) info;
+ dev->dev.driver_data = (void *) info;
return try_smi_init(info);
}
@@ -2319,14 +2388,16 @@ static int __devexit ipmi_of_remove(struct of_device *dev)
static struct of_device_id ipmi_match[] =
{
- { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS },
- { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC },
- { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT },
+ { .type = "ipmi", .compatible = "ipmi-kcs",
+ .data = (void *)(unsigned long) SI_KCS },
+ { .type = "ipmi", .compatible = "ipmi-smic",
+ .data = (void *)(unsigned long) SI_SMIC },
+ { .type = "ipmi", .compatible = "ipmi-bt",
+ .data = (void *)(unsigned long) SI_BT },
{},
};
-static struct of_platform_driver ipmi_of_platform_driver =
-{
+static struct of_platform_driver ipmi_of_platform_driver = {
.name = "ipmi",
.match_table = ipmi_match,
.probe = ipmi_of_probe,
@@ -2347,32 +2418,32 @@ static int try_get_dev_id(struct smi_info *smi_info)
if (!resp)
return -ENOMEM;
- /* Do a Get Device ID command, since it comes back with some
- useful info. */
+ /*
+ * Do a Get Device ID command, since it comes back with some
+ * useful info.
+ */
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_DEVICE_ID_CMD;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
- for (;;)
- {
+ for (;;) {
if (smi_result == SI_SM_CALL_WITH_DELAY ||
smi_result == SI_SM_CALL_WITH_TICK_DELAY) {
schedule_timeout_uninterruptible(1);
smi_result = smi_info->handlers->event(
smi_info->si_sm, 100);
- }
- else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
- {
+ } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
smi_result = smi_info->handlers->event(
smi_info->si_sm, 0);
- }
- else
+ } else
break;
}
if (smi_result == SI_SM_HOSED) {
- /* We couldn't get the state machine to run, so whatever's at
- the port is probably not an IPMI SMI interface. */
+ /*
+ * We couldn't get the state machine to run, so whatever's at
+ * the port is probably not an IPMI SMI interface.
+ */
rv = -ENODEV;
goto out;
}
@@ -2405,30 +2476,28 @@ static int stat_file_read_proc(char *page, char **start, off_t off,
out += sprintf(out, "interrupts_enabled: %d\n",
smi->irq && !smi->interrupt_disabled);
- out += sprintf(out, "short_timeouts: %ld\n",
- smi->short_timeouts);
- out += sprintf(out, "long_timeouts: %ld\n",
- smi->long_timeouts);
- out += sprintf(out, "timeout_restarts: %ld\n",
- smi->timeout_restarts);
- out += sprintf(out, "idles: %ld\n",
- smi->idles);
- out += sprintf(out, "interrupts: %ld\n",
- smi->interrupts);
- out += sprintf(out, "attentions: %ld\n",
- smi->attentions);
- out += sprintf(out, "flag_fetches: %ld\n",
- smi->flag_fetches);
- out += sprintf(out, "hosed_count: %ld\n",
- smi->hosed_count);
- out += sprintf(out, "complete_transactions: %ld\n",
- smi->complete_transactions);
- out += sprintf(out, "events: %ld\n",
- smi->events);
- out += sprintf(out, "watchdog_pretimeouts: %ld\n",
- smi->watchdog_pretimeouts);
- out += sprintf(out, "incoming_messages: %ld\n",
- smi->incoming_messages);
+ out += sprintf(out, "short_timeouts: %u\n",
+ smi_get_stat(smi, short_timeouts));
+ out += sprintf(out, "long_timeouts: %u\n",
+ smi_get_stat(smi, long_timeouts));
+ out += sprintf(out, "idles: %u\n",
+ smi_get_stat(smi, idles));
+ out += sprintf(out, "interrupts: %u\n",
+ smi_get_stat(smi, interrupts));
+ out += sprintf(out, "attentions: %u\n",
+ smi_get_stat(smi, attentions));
+ out += sprintf(out, "flag_fetches: %u\n",
+ smi_get_stat(smi, flag_fetches));
+ out += sprintf(out, "hosed_count: %u\n",
+ smi_get_stat(smi, hosed_count));
+ out += sprintf(out, "complete_transactions: %u\n",
+ smi_get_stat(smi, complete_transactions));
+ out += sprintf(out, "events: %u\n",
+ smi_get_stat(smi, events));
+ out += sprintf(out, "watchdog_pretimeouts: %u\n",
+ smi_get_stat(smi, watchdog_pretimeouts));
+ out += sprintf(out, "incoming_messages: %u\n",
+ smi_get_stat(smi, incoming_messages));
return out - page;
}
@@ -2460,7 +2529,7 @@ static int param_read_proc(char *page, char **start, off_t off,
static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
{
smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) |
- RECEIVE_MSG_AVAIL);
+ RECEIVE_MSG_AVAIL);
return 1;
}
@@ -2502,10 +2571,9 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) {
smi_info->oem_data_avail_handler =
oem_data_avail_to_receive_msg_avail;
- }
- else if (ipmi_version_major(id) < 1 ||
- (ipmi_version_major(id) == 1 &&
- ipmi_version_minor(id) < 5)) {
+ } else if (ipmi_version_major(id) < 1 ||
+ (ipmi_version_major(id) == 1 &&
+ ipmi_version_minor(id) < 5)) {
smi_info->oem_data_avail_handler =
oem_data_avail_to_receive_msg_avail;
}
@@ -2597,8 +2665,10 @@ static void setup_xaction_handlers(struct smi_info *smi_info)
static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
{
if (smi_info->intf) {
- /* The timer and thread are only running if the
- interface has been started up and registered. */
+ /*
+ * The timer and thread are only running if the
+ * interface has been started up and registered.
+ */
if (smi_info->thread != NULL)
kthread_stop(smi_info->thread);
del_timer_sync(&smi_info->si_timer);
@@ -2676,6 +2746,7 @@ static int is_new_interface(struct smi_info *info)
static int try_smi_init(struct smi_info *new_smi)
{
int rv;
+ int i;
if (new_smi->addr_source) {
printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"
@@ -2722,7 +2793,7 @@ static int try_smi_init(struct smi_info *new_smi)
/* Allocate the state machine's data and initialize it. */
new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
if (!new_smi->si_sm) {
- printk(" Could not allocate state machine memory\n");
+ printk(KERN_ERR "Could not allocate state machine memory\n");
rv = -ENOMEM;
goto out_err;
}
@@ -2732,13 +2803,12 @@ static int try_smi_init(struct smi_info *new_smi)
/* Now that we know the I/O size, we can set up the I/O. */
rv = new_smi->io_setup(new_smi);
if (rv) {
- printk(" Could not set up I/O space\n");
+ printk(KERN_ERR "Could not set up I/O space\n");
goto out_err;
}
spin_lock_init(&(new_smi->si_lock));
spin_lock_init(&(new_smi->msg_lock));
- spin_lock_init(&(new_smi->count_lock));
/* Do low-level detection first. */
if (new_smi->handlers->detect(new_smi->si_sm)) {
@@ -2749,8 +2819,10 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err;
}
- /* Attempt a get device id command. If it fails, we probably
- don't have a BMC here. */
+ /*
+ * Attempt a get device id command. If it fails, we probably
+ * don't have a BMC here.
+ */
rv = try_get_dev_id(new_smi);
if (rv) {
if (new_smi->addr_source)
@@ -2767,22 +2839,28 @@ static int try_smi_init(struct smi_info *new_smi)
new_smi->curr_msg = NULL;
atomic_set(&new_smi->req_events, 0);
new_smi->run_to_completion = 0;
+ for (i = 0; i < SI_NUM_STATS; i++)
+ atomic_set(&new_smi->stats[i], 0);
new_smi->interrupt_disabled = 0;
atomic_set(&new_smi->stop_operation, 0);
new_smi->intf_num = smi_num;
smi_num++;
- /* Start clearing the flags before we enable interrupts or the
- timer to avoid racing with the timer. */
+ /*
+ * Start clearing the flags before we enable interrupts or the
+ * timer to avoid racing with the timer.
+ */
start_clear_flags(new_smi);
/* IRQ is defined to be set when non-zero. */
if (new_smi->irq)
new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
if (!new_smi->dev) {
- /* If we don't already have a device from something
- * else (like PCI), then register a new one. */
+ /*
+ * If we don't already have a device from something
+ * else (like PCI), then register a new one.
+ */
new_smi->pdev = platform_device_alloc("ipmi_si",
new_smi->intf_num);
if (rv) {
@@ -2820,7 +2898,7 @@ static int try_smi_init(struct smi_info *new_smi)
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
- type_file_read_proc, NULL,
+ type_file_read_proc,
new_smi, THIS_MODULE);
if (rv) {
printk(KERN_ERR
@@ -2830,7 +2908,7 @@ static int try_smi_init(struct smi_info *new_smi)
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
- stat_file_read_proc, NULL,
+ stat_file_read_proc,
new_smi, THIS_MODULE);
if (rv) {
printk(KERN_ERR
@@ -2840,7 +2918,7 @@ static int try_smi_init(struct smi_info *new_smi)
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
- param_read_proc, NULL,
+ param_read_proc,
new_smi, THIS_MODULE);
if (rv) {
printk(KERN_ERR
@@ -2853,7 +2931,8 @@ static int try_smi_init(struct smi_info *new_smi)
mutex_unlock(&smi_infos_lock);
- printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]);
+ printk(KERN_INFO "IPMI %s interface initialized\n",
+ si_to_str[new_smi->si_type]);
return 0;
@@ -2868,9 +2947,11 @@ static int try_smi_init(struct smi_info *new_smi)
if (new_smi->irq_cleanup)
new_smi->irq_cleanup(new_smi);
- /* Wait until we know that we are out of any interrupt
- handlers might have been running before we freed the
- interrupt. */
+ /*
+ * Wait until we know that we are out of any interrupt
+ * handlers might have been running before we freed the
+ * interrupt.
+ */
synchronize_sched();
if (new_smi->si_sm) {
@@ -2942,11 +3023,10 @@ static __devinit int init_ipmi_si(void)
#ifdef CONFIG_PCI
rv = pci_register_driver(&ipmi_pci_driver);
- if (rv){
+ if (rv)
printk(KERN_ERR
"init_ipmi_si: Unable to register PCI driver: %d\n",
rv);
- }
#endif
#ifdef CONFIG_PPC_OF
@@ -2975,7 +3055,8 @@ static __devinit int init_ipmi_si(void)
of_unregister_platform_driver(&ipmi_of_platform_driver);
#endif
driver_unregister(&ipmi_driver);
- printk("ipmi_si: Unable to find any System Interface(s)\n");
+ printk(KERN_WARNING
+ "ipmi_si: Unable to find any System Interface(s)\n");
return -ENODEV;
} else {
mutex_unlock(&smi_infos_lock);
@@ -2997,13 +3078,17 @@ static void cleanup_one_si(struct smi_info *to_clean)
/* Tell the driver that we are shutting down. */
atomic_inc(&to_clean->stop_operation);
- /* Make sure the timer and thread are stopped and will not run
- again. */
+ /*
+ * Make sure the timer and thread are stopped and will not run
+ * again.
+ */
wait_for_timer_and_thread(to_clean);
- /* Timeouts are stopped, now make sure the interrupts are off
- for the device. A little tricky with locks to make sure
- there are no races. */
+ /*
+ * Timeouts are stopped, now make sure the interrupts are off
+ * for the device. A little tricky with locks to make sure
+ * there are no races.
+ */
spin_lock_irqsave(&to_clean->si_lock, flags);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
spin_unlock_irqrestore(&to_clean->si_lock, flags);
@@ -3074,4 +3159,5 @@ module_exit(cleanup_ipmi_si);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
-MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces.");
+MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT"
+ " system interfaces.");
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
index 4b731b24dc16..df89f73475fb 100644
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -34,22 +34,27 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* This is defined by the state machines themselves, it is an opaque
- data type for them to use. */
+/*
+ * This is defined by the state machines themselves, it is an opaque
+ * data type for them to use.
+ */
struct si_sm_data;
-/* The structure for doing I/O in the state machine. The state
- machine doesn't have the actual I/O routines, they are done through
- this interface. */
-struct si_sm_io
-{
+/*
+ * The structure for doing I/O in the state machine. The state
+ * machine doesn't have the actual I/O routines, they are done through
+ * this interface.
+ */
+struct si_sm_io {
unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset);
void (*outputb)(struct si_sm_io *io,
unsigned int offset,
unsigned char b);
- /* Generic info used by the actual handling routines, the
- state machine shouldn't touch these. */
+ /*
+ * Generic info used by the actual handling routines, the
+ * state machine shouldn't touch these.
+ */
void __iomem *addr;
int regspacing;
int regsize;
@@ -59,53 +64,67 @@ struct si_sm_io
};
/* Results of SMI events. */
-enum si_sm_result
-{
+enum si_sm_result {
SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */
- SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */
+ SI_SM_CALL_WITH_TICK_DELAY,/* Delay >=1 tick before calling again. */
SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */
SI_SM_IDLE, /* The SM is in idle state. */
SI_SM_HOSED, /* The hardware violated the state machine. */
- SI_SM_ATTN /* The hardware is asserting attn and the
- state machine is idle. */
+
+ /*
+ * The hardware is asserting attn and the state machine is
+ * idle.
+ */
+ SI_SM_ATTN
};
/* Handlers for the SMI state machine. */
-struct si_sm_handlers
-{
- /* Put the version number of the state machine here so the
- upper layer can print it. */
+struct si_sm_handlers {
+ /*
+ * Put the version number of the state machine here so the
+ * upper layer can print it.
+ */
char *version;
- /* Initialize the data and return the amount of I/O space to
- reserve for the space. */
+ /*
+ * Initialize the data and return the amount of I/O space to
+ * reserve for the space.
+ */
unsigned int (*init_data)(struct si_sm_data *smi,
struct si_sm_io *io);
- /* Start a new transaction in the state machine. This will
- return -2 if the state machine is not idle, -1 if the size
- is invalid (to large or too small), or 0 if the transaction
- is successfully completed. */
+ /*
+ * Start a new transaction in the state machine. This will
+ * return -2 if the state machine is not idle, -1 if the size
+ * is invalid (to large or too small), or 0 if the transaction
+ * is successfully completed.
+ */
int (*start_transaction)(struct si_sm_data *smi,
unsigned char *data, unsigned int size);
- /* Return the results after the transaction. This will return
- -1 if the buffer is too small, zero if no transaction is
- present, or the actual length of the result data. */
+ /*
+ * Return the results after the transaction. This will return
+ * -1 if the buffer is too small, zero if no transaction is
+ * present, or the actual length of the result data.
+ */
int (*get_result)(struct si_sm_data *smi,
unsigned char *data, unsigned int length);
- /* Call this periodically (for a polled interface) or upon
- receiving an interrupt (for a interrupt-driven interface).
- If interrupt driven, you should probably poll this
- periodically when not in idle state. This should be called
- with the time that passed since the last call, if it is
- significant. Time is in microseconds. */
+ /*
+ * Call this periodically (for a polled interface) or upon
+ * receiving an interrupt (for a interrupt-driven interface).
+ * If interrupt driven, you should probably poll this
+ * periodically when not in idle state. This should be called
+ * with the time that passed since the last call, if it is
+ * significant. Time is in microseconds.
+ */
enum si_sm_result (*event)(struct si_sm_data *smi, long time);
- /* Attempt to detect an SMI. Returns 0 on success or nonzero
- on failure. */
+ /*
+ * Attempt to detect an SMI. Returns 0 on success or nonzero
+ * on failure.
+ */
int (*detect)(struct si_sm_data *smi);
/* The interface is shutting down, so clean it up. */
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index e64ea7d25d24..faed92971907 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -85,6 +85,7 @@ enum smic_states {
/* SMIC Flags Register Bits */
#define SMIC_RX_DATA_READY 0x80
#define SMIC_TX_DATA_READY 0x40
+
/*
* SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by
* a few systems, and then only by Systems Management
@@ -104,23 +105,22 @@ enum smic_states {
#define EC_ILLEGAL_COMMAND 0x04
#define EC_BUFFER_FULL 0x05
-struct si_sm_data
-{
+struct si_sm_data {
enum smic_states state;
struct si_sm_io *io;
- unsigned char write_data[MAX_SMIC_WRITE_SIZE];
- int write_pos;
- int write_count;
- int orig_write_count;
- unsigned char read_data[MAX_SMIC_READ_SIZE];
- int read_pos;
- int truncated;
- unsigned int error_retries;
- long smic_timeout;
+ unsigned char write_data[MAX_SMIC_WRITE_SIZE];
+ int write_pos;
+ int write_count;
+ int orig_write_count;
+ unsigned char read_data[MAX_SMIC_READ_SIZE];
+ int read_pos;
+ int truncated;
+ unsigned int error_retries;
+ long smic_timeout;
};
-static unsigned int init_smic_data (struct si_sm_data *smic,
- struct si_sm_io *io)
+static unsigned int init_smic_data(struct si_sm_data *smic,
+ struct si_sm_io *io)
{
smic->state = SMIC_IDLE;
smic->io = io;
@@ -150,11 +150,10 @@ static int start_smic_transaction(struct si_sm_data *smic,
return IPMI_NOT_IN_MY_STATE_ERR;
if (smic_debug & SMIC_DEBUG_MSG) {
- printk(KERN_INFO "start_smic_transaction -");
- for (i = 0; i < size; i ++) {
- printk (" %02x", (unsigned char) (data [i]));
- }
- printk ("\n");
+ printk(KERN_DEBUG "start_smic_transaction -");
+ for (i = 0; i < size; i++)
+ printk(" %02x", (unsigned char) data[i]);
+ printk("\n");
}
smic->error_retries = 0;
memcpy(smic->write_data, data, size);
@@ -173,11 +172,10 @@ static int smic_get_result(struct si_sm_data *smic,
int i;
if (smic_debug & SMIC_DEBUG_MSG) {
- printk (KERN_INFO "smic_get result -");
- for (i = 0; i < smic->read_pos; i ++) {
- printk (" %02x", (smic->read_data [i]));
- }
- printk ("\n");
+ printk(KERN_DEBUG "smic_get result -");
+ for (i = 0; i < smic->read_pos; i++)
+ printk(" %02x", smic->read_data[i]);
+ printk("\n");
}
if (length < smic->read_pos) {
smic->read_pos = length;
@@ -223,8 +221,8 @@ static inline void write_smic_control(struct si_sm_data *smic,
smic->io->outputb(smic->io, 1, control);
}
-static inline void write_si_sm_data (struct si_sm_data *smic,
- unsigned char data)
+static inline void write_si_sm_data(struct si_sm_data *smic,
+ unsigned char data)
{
smic->io->outputb(smic->io, 0, data);
}
@@ -233,10 +231,9 @@ static inline void start_error_recovery(struct si_sm_data *smic, char *reason)
{
(smic->error_retries)++;
if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {
- if (smic_debug & SMIC_DEBUG_ENABLE) {
+ if (smic_debug & SMIC_DEBUG_ENABLE)
printk(KERN_WARNING
"ipmi_smic_drv: smic hosed: %s\n", reason);
- }
smic->state = SMIC_HOSED;
} else {
smic->write_count = smic->orig_write_count;
@@ -254,14 +251,14 @@ static inline void write_next_byte(struct si_sm_data *smic)
(smic->write_count)--;
}
-static inline void read_next_byte (struct si_sm_data *smic)
+static inline void read_next_byte(struct si_sm_data *smic)
{
if (smic->read_pos >= MAX_SMIC_READ_SIZE) {
- read_smic_data (smic);
+ read_smic_data(smic);
smic->truncated = 1;
} else {
smic->read_data[smic->read_pos] = read_smic_data(smic);
- (smic->read_pos)++;
+ smic->read_pos++;
}
}
@@ -336,7 +333,7 @@ static inline void read_next_byte (struct si_sm_data *smic)
SMIC_SC_SMS_RD_END 0xC6
*/
-static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
+static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
{
unsigned char status;
unsigned char flags;
@@ -347,13 +344,15 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
return SI_SM_HOSED;
}
if (smic->state != SMIC_IDLE) {
- if (smic_debug & SMIC_DEBUG_STATES) {
- printk(KERN_INFO
+ if (smic_debug & SMIC_DEBUG_STATES)
+ printk(KERN_DEBUG
"smic_event - smic->smic_timeout = %ld,"
" time = %ld\n",
smic->smic_timeout, time);
- }
-/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */
+ /*
+ * FIXME: smic_event is sometimes called with time >
+ * SMIC_RETRY_TIMEOUT
+ */
if (time < SMIC_RETRY_TIMEOUT) {
smic->smic_timeout -= time;
if (smic->smic_timeout < 0) {
@@ -366,9 +365,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
if (flags & SMIC_FLAG_BSY)
return SI_SM_CALL_WITH_DELAY;
- status = read_smic_status (smic);
+ status = read_smic_status(smic);
if (smic_debug & SMIC_DEBUG_STATES)
- printk(KERN_INFO
+ printk(KERN_DEBUG
"smic_event - state = %d, flags = 0x%02x,"
" status = 0x%02x\n",
smic->state, flags, status);
@@ -377,9 +376,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
case SMIC_IDLE:
/* in IDLE we check for available messages */
if (flags & SMIC_SMS_DATA_AVAIL)
- {
return SI_SM_ATTN;
- }
return SI_SM_IDLE;
case SMIC_START_OP:
@@ -391,7 +388,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
case SMIC_OP_OK:
if (status != SMIC_SC_SMS_READY) {
- /* this should not happen */
+ /* this should not happen */
start_error_recovery(smic,
"state = SMIC_OP_OK,"
" status != SMIC_SC_SMS_READY");
@@ -411,8 +408,10 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
"status != SMIC_SC_SMS_WR_START");
return SI_SM_CALL_WITH_DELAY;
}
- /* we must not issue WR_(NEXT|END) unless
- TX_DATA_READY is set */
+ /*
+ * we must not issue WR_(NEXT|END) unless
+ * TX_DATA_READY is set
+ * */
if (flags & SMIC_TX_DATA_READY) {
if (smic->write_count == 1) {
/* last byte */
@@ -424,10 +423,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
}
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
- }
- else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_WRITE_NEXT:
@@ -442,52 +439,48 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
if (smic->write_count == 1) {
write_smic_control(smic, SMIC_CC_SMS_WR_END);
smic->state = SMIC_WRITE_END;
- }
- else {
+ } else {
write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
smic->state = SMIC_WRITE_NEXT;
}
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
- }
- else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_WRITE_END:
if (status != SMIC_SC_SMS_WR_END) {
- start_error_recovery (smic,
- "state = SMIC_WRITE_END, "
- "status != SMIC_SC_SMS_WR_END");
+ start_error_recovery(smic,
+ "state = SMIC_WRITE_END, "
+ "status != SMIC_SC_SMS_WR_END");
return SI_SM_CALL_WITH_DELAY;
}
/* data register holds an error code */
data = read_smic_data(smic);
if (data != 0) {
- if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_INFO
+ if (smic_debug & SMIC_DEBUG_ENABLE)
+ printk(KERN_DEBUG
"SMIC_WRITE_END: data = %02x\n", data);
- }
start_error_recovery(smic,
"state = SMIC_WRITE_END, "
"data != SUCCESS");
return SI_SM_CALL_WITH_DELAY;
- } else {
+ } else
smic->state = SMIC_WRITE2READ;
- }
break;
case SMIC_WRITE2READ:
- /* we must wait for RX_DATA_READY to be set before we
- can continue */
+ /*
+ * we must wait for RX_DATA_READY to be set before we
+ * can continue
+ */
if (flags & SMIC_RX_DATA_READY) {
write_smic_control(smic, SMIC_CC_SMS_RD_START);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_START;
- } else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_READ_START:
@@ -502,15 +495,16 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_NEXT;
- } else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_READ_NEXT:
switch (status) {
- /* smic tells us that this is the last byte to be read
- --> clean up */
+ /*
+ * smic tells us that this is the last byte to be read
+ * --> clean up
+ */
case SMIC_SC_SMS_RD_END:
read_next_byte(smic);
write_smic_control(smic, SMIC_CC_SMS_RD_END);
@@ -523,9 +517,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_NEXT;
- } else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
default:
start_error_recovery(
@@ -546,10 +539,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
data = read_smic_data(smic);
/* data register holds an error code */
if (data != 0) {
- if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_INFO
+ if (smic_debug & SMIC_DEBUG_ENABLE)
+ printk(KERN_DEBUG
"SMIC_READ_END: data = %02x\n", data);
- }
start_error_recovery(smic,
"state = SMIC_READ_END, "
"data != SUCCESS");
@@ -565,7 +557,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
default:
if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_WARNING "smic->state = %d\n", smic->state);
+ printk(KERN_DEBUG "smic->state = %d\n", smic->state);
start_error_recovery(smic, "state = UNKNOWN");
return SI_SM_CALL_WITH_DELAY;
}
@@ -576,10 +568,12 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
static int smic_detect(struct si_sm_data *smic)
{
- /* It's impossible for the SMIC fnags register to be all 1's,
- (assuming a properly functioning, self-initialized BMC)
- but that's what you get from reading a bogus address, so we
- test that first. */
+ /*
+ * It's impossible for the SMIC fnags register to be all 1's,
+ * (assuming a properly functioning, self-initialized BMC)
+ * but that's what you get from reading a bogus address, so we
+ * test that first.
+ */
if (read_smic_flags(smic) == 0xff)
return 1;
@@ -595,8 +589,7 @@ static int smic_size(void)
return sizeof(struct si_sm_data);
}
-struct si_sm_handlers smic_smi_handlers =
-{
+struct si_sm_handlers smic_smi_handlers = {
.init_data = init_smic_data,
.start_transaction = start_smic_transaction,
.get_result = smic_get_result,
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 8f45ca9235ad..1b9a87047817 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -54,13 +54,15 @@
#include <asm/atomic.h>
#ifdef CONFIG_X86
-/* This is ugly, but I've determined that x86 is the only architecture
- that can reasonably support the IPMI NMI watchdog timeout at this
- time. If another architecture adds this capability somehow, it
- will have to be a somewhat different mechanism and I have no idea
- how it will work. So in the unlikely event that another
- architecture supports this, we can figure out a good generic
- mechanism for it at that time. */
+/*
+ * This is ugly, but I've determined that x86 is the only architecture
+ * that can reasonably support the IPMI NMI watchdog timeout at this
+ * time. If another architecture adds this capability somehow, it
+ * will have to be a somewhat different mechanism and I have no idea
+ * how it will work. So in the unlikely event that another
+ * architecture supports this, we can figure out a good generic
+ * mechanism for it at that time.
+ */
#include <asm/kdebug.h>
#define HAVE_DIE_NMI
#endif
@@ -95,9 +97,8 @@
/* Operations that can be performed on a pretimout. */
#define WDOG_PREOP_NONE 0
#define WDOG_PREOP_PANIC 1
-#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to
- read. Doesn't work in NMI
- mode. */
+/* Cause data to be available to read. Doesn't work in NMI mode. */
+#define WDOG_PREOP_GIVE_DATA 2
/* Actions to perform on a full timeout. */
#define WDOG_SET_TIMEOUT_ACT(byte, use) \
@@ -108,8 +109,10 @@
#define WDOG_TIMEOUT_POWER_DOWN 2
#define WDOG_TIMEOUT_POWER_CYCLE 3
-/* Byte 3 of the get command, byte 4 of the get response is the
- pre-timeout in seconds. */
+/*
+ * Byte 3 of the get command, byte 4 of the get response is the
+ * pre-timeout in seconds.
+ */
/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
#define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1)
@@ -118,11 +121,13 @@
#define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4)
#define WDOG_EXPIRE_CLEAR_OEM (1 << 5)
-/* Setting/getting the watchdog timer value. This is for bytes 5 and
- 6 (the timeout time) of the set command, and bytes 6 and 7 (the
- timeout time) and 8 and 9 (the current countdown value) of the
- response. The timeout value is given in seconds (in the command it
- is 100ms intervals). */
+/*
+ * Setting/getting the watchdog timer value. This is for bytes 5 and
+ * 6 (the timeout time) of the set command, and bytes 6 and 7 (the
+ * timeout time) and 8 and 9 (the current countdown value) of the
+ * response. The timeout value is given in seconds (in the command it
+ * is 100ms intervals).
+ */
#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
(byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
#define WDOG_GET_TIMEOUT(byte1, byte2) \
@@ -184,8 +189,10 @@ static int ipmi_set_timeout(int do_heartbeat);
static void ipmi_register_watchdog(int ipmi_intf);
static void ipmi_unregister_watchdog(int ipmi_intf);
-/* If true, the driver will start running as soon as it is configured
- and ready. */
+/*
+ * If true, the driver will start running as soon as it is configured
+ * and ready.
+ */
static int start_now;
static int set_param_int(const char *val, struct kernel_param *kp)
@@ -309,10 +316,12 @@ static int ipmi_ignore_heartbeat;
/* Is someone using the watchdog? Only one user is allowed. */
static unsigned long ipmi_wdog_open;
-/* If set to 1, the heartbeat command will set the state to reset and
- start the timer. The timer doesn't normally run when the driver is
- first opened until the heartbeat is set the first time, this
- variable is used to accomplish this. */
+/*
+ * If set to 1, the heartbeat command will set the state to reset and
+ * start the timer. The timer doesn't normally run when the driver is
+ * first opened until the heartbeat is set the first time, this
+ * variable is used to accomplish this.
+ */
static int ipmi_start_timer_on_heartbeat;
/* IPMI version of the BMC. */
@@ -329,10 +338,12 @@ static int nmi_handler_registered;
static int ipmi_heartbeat(void);
-/* We use a mutex to make sure that only one thing can send a set
- timeout at one time, because we only have one copy of the data.
- The mutex is claimed when the set_timeout is sent and freed
- when both messages are free. */
+/*
+ * We use a mutex to make sure that only one thing can send a set
+ * timeout at one time, because we only have one copy of the data.
+ * The mutex is claimed when the set_timeout is sent and freed
+ * when both messages are free.
+ */
static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
static DEFINE_MUTEX(set_timeout_lock);
static DECLARE_COMPLETION(set_timeout_wait);
@@ -346,15 +357,13 @@ static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
if (atomic_dec_and_test(&set_timeout_tofree))
complete(&set_timeout_wait);
}
-static struct ipmi_smi_msg set_timeout_smi_msg =
-{
+static struct ipmi_smi_msg set_timeout_smi_msg = {
.done = set_timeout_free_smi
};
-static struct ipmi_recv_msg set_timeout_recv_msg =
-{
+static struct ipmi_recv_msg set_timeout_recv_msg = {
.done = set_timeout_free_recv
};
-
+
static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
struct ipmi_recv_msg *recv_msg,
int *send_heartbeat_now)
@@ -373,13 +382,14 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
if ((ipmi_version_major > 1)
- || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
- {
+ || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) {
/* This is an IPMI 1.5-only feature. */
data[0] |= WDOG_DONT_STOP_ON_SET;
} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
- /* In ipmi 1.0, setting the timer stops the watchdog, we
- need to start it back up again. */
+ /*
+ * In ipmi 1.0, setting the timer stops the watchdog, we
+ * need to start it back up again.
+ */
hbnow = 1;
}
@@ -465,12 +475,10 @@ static void panic_recv_free(struct ipmi_recv_msg *msg)
atomic_dec(&panic_done_count);
}
-static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
-{
+static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = {
.done = panic_smi_free
};
-static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
-{
+static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = {
.done = panic_recv_free
};
@@ -480,8 +488,10 @@ static void panic_halt_ipmi_heartbeat(void)
struct ipmi_system_interface_addr addr;
int rv;
- /* Don't reset the timer if we have the timer turned off, that
- re-enables the watchdog. */
+ /*
+ * Don't reset the timer if we have the timer turned off, that
+ * re-enables the watchdog.
+ */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
return;
@@ -505,19 +515,19 @@ static void panic_halt_ipmi_heartbeat(void)
atomic_add(2, &panic_done_count);
}
-static struct ipmi_smi_msg panic_halt_smi_msg =
-{
+static struct ipmi_smi_msg panic_halt_smi_msg = {
.done = panic_smi_free
};
-static struct ipmi_recv_msg panic_halt_recv_msg =
-{
+static struct ipmi_recv_msg panic_halt_recv_msg = {
.done = panic_recv_free
};
-/* Special call, doesn't claim any locks. This is only to be called
- at panic or halt time, in run-to-completion mode, when the caller
- is the only CPU and the only thing that will be going is these IPMI
- calls. */
+/*
+ * Special call, doesn't claim any locks. This is only to be called
+ * at panic or halt time, in run-to-completion mode, when the caller
+ * is the only CPU and the only thing that will be going is these IPMI
+ * calls.
+ */
static void panic_halt_ipmi_set_timeout(void)
{
int send_heartbeat_now;
@@ -540,10 +550,12 @@ static void panic_halt_ipmi_set_timeout(void)
ipmi_poll_interface(watchdog_user);
}
-/* We use a semaphore to make sure that only one thing can send a
- heartbeat at one time, because we only have one copy of the data.
- The semaphore is claimed when the set_timeout is sent and freed
- when both messages are free. */
+/*
+ * We use a mutex to make sure that only one thing can send a
+ * heartbeat at one time, because we only have one copy of the data.
+ * The semaphore is claimed when the set_timeout is sent and freed
+ * when both messages are free.
+ */
static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
static DEFINE_MUTEX(heartbeat_lock);
static DECLARE_COMPLETION(heartbeat_wait);
@@ -557,15 +569,13 @@ static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
if (atomic_dec_and_test(&heartbeat_tofree))
complete(&heartbeat_wait);
}
-static struct ipmi_smi_msg heartbeat_smi_msg =
-{
+static struct ipmi_smi_msg heartbeat_smi_msg = {
.done = heartbeat_free_smi
};
-static struct ipmi_recv_msg heartbeat_recv_msg =
-{
+static struct ipmi_recv_msg heartbeat_recv_msg = {
.done = heartbeat_free_recv
};
-
+
static int ipmi_heartbeat(void)
{
struct kernel_ipmi_msg msg;
@@ -580,10 +590,12 @@ static int ipmi_heartbeat(void)
ipmi_watchdog_state = action_val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
} else if (pretimeout_since_last_heartbeat) {
- /* A pretimeout occurred, make sure we set the timeout.
- We don't want to set the action, though, we want to
- leave that alone (thus it can't be combined with the
- above operation. */
+ /*
+ * A pretimeout occurred, make sure we set the timeout.
+ * We don't want to set the action, though, we want to
+ * leave that alone (thus it can't be combined with the
+ * above operation.
+ */
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
}
@@ -591,8 +603,10 @@ static int ipmi_heartbeat(void)
atomic_set(&heartbeat_tofree, 2);
- /* Don't reset the timer if we have the timer turned off, that
- re-enables the watchdog. */
+ /*
+ * Don't reset the timer if we have the timer turned off, that
+ * re-enables the watchdog.
+ */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
mutex_unlock(&heartbeat_lock);
return 0;
@@ -625,10 +639,12 @@ static int ipmi_heartbeat(void)
wait_for_completion(&heartbeat_wait);
if (heartbeat_recv_msg.msg.data[0] != 0) {
- /* Got an error in the heartbeat response. It was already
- reported in ipmi_wdog_msg_handler, but we should return
- an error here. */
- rv = -EINVAL;
+ /*
+ * Got an error in the heartbeat response. It was already
+ * reported in ipmi_wdog_msg_handler, but we should return
+ * an error here.
+ */
+ rv = -EINVAL;
}
mutex_unlock(&heartbeat_lock);
@@ -636,8 +652,7 @@ static int ipmi_heartbeat(void)
return rv;
}
-static struct watchdog_info ident =
-{
+static struct watchdog_info ident = {
.options = 0, /* WDIOF_SETTIMEOUT, */
.firmware_version = 1,
.identity = "IPMI"
@@ -650,7 +665,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file,
int i;
int val;
- switch(cmd) {
+ switch (cmd) {
case WDIOC_GETSUPPORT:
i = copy_to_user(argp, &ident, sizeof(ident));
return i ? -EFAULT : 0;
@@ -690,15 +705,13 @@ static int ipmi_ioctl(struct inode *inode, struct file *file,
i = copy_from_user(&val, argp, sizeof(int));
if (i)
return -EFAULT;
- if (val & WDIOS_DISABLECARD)
- {
+ if (val & WDIOS_DISABLECARD) {
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
ipmi_start_timer_on_heartbeat = 0;
}
- if (val & WDIOS_ENABLECARD)
- {
+ if (val & WDIOS_ENABLECARD) {
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
}
@@ -724,13 +737,13 @@ static ssize_t ipmi_write(struct file *file,
int rv;
if (len) {
- if (!nowayout) {
- size_t i;
+ if (!nowayout) {
+ size_t i;
/* In case it was set long ago */
expect_close = 0;
- for (i = 0; i != len; i++) {
+ for (i = 0; i != len; i++) {
char c;
if (get_user(c, buf + i))
@@ -758,15 +771,17 @@ static ssize_t ipmi_read(struct file *file,
if (count <= 0)
return 0;
- /* Reading returns if the pretimeout has gone off, and it only does
- it once per pretimeout. */
+ /*
+ * Reading returns if the pretimeout has gone off, and it only does
+ * it once per pretimeout.
+ */
spin_lock(&ipmi_read_lock);
if (!data_to_read) {
if (file->f_flags & O_NONBLOCK) {
rv = -EAGAIN;
goto out;
}
-
+
init_waitqueue_entry(&wait, current);
add_wait_queue(&read_q, &wait);
while (!data_to_read) {
@@ -776,7 +791,7 @@ static ssize_t ipmi_read(struct file *file,
spin_lock(&ipmi_read_lock);
}
remove_wait_queue(&read_q, &wait);
-
+
if (signal_pending(current)) {
rv = -ERESTARTSYS;
goto out;
@@ -799,25 +814,27 @@ static ssize_t ipmi_read(struct file *file,
static int ipmi_open(struct inode *ino, struct file *filep)
{
- switch (iminor(ino)) {
- case WATCHDOG_MINOR:
+ switch (iminor(ino)) {
+ case WATCHDOG_MINOR:
if (test_and_set_bit(0, &ipmi_wdog_open))
- return -EBUSY;
+ return -EBUSY;
- /* Don't start the timer now, let it start on the
- first heartbeat. */
+ /*
+ * Don't start the timer now, let it start on the
+ * first heartbeat.
+ */
ipmi_start_timer_on_heartbeat = 1;
return nonseekable_open(ino, filep);
default:
return (-ENODEV);
- }
+ }
}
static unsigned int ipmi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
-
+
poll_wait(file, &read_q, wait);
spin_lock(&ipmi_read_lock);
@@ -851,7 +868,7 @@ static int ipmi_close(struct inode *ino, struct file *filep)
clear_bit(0, &ipmi_wdog_open);
}
- ipmi_fasync (-1, filep, 0);
+ ipmi_fasync(-1, filep, 0);
expect_close = 0;
return 0;
@@ -882,7 +899,7 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
msg->msg.data[0],
msg->msg.cmd);
}
-
+
ipmi_free_recv_msg(msg);
}
@@ -902,14 +919,14 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data)
}
}
- /* On some machines, the heartbeat will give
- an error and not work unless we re-enable
- the timer. So do so. */
+ /*
+ * On some machines, the heartbeat will give an error and not
+ * work unless we re-enable the timer. So do so.
+ */
pretimeout_since_last_heartbeat = 1;
}
-static struct ipmi_user_hndl ipmi_hndlrs =
-{
+static struct ipmi_user_hndl ipmi_hndlrs = {
.ipmi_recv_hndl = ipmi_wdog_msg_handler,
.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
};
@@ -949,8 +966,10 @@ static void ipmi_register_watchdog(int ipmi_intf)
int old_timeout = timeout;
int old_preop_val = preop_val;
- /* Set the pretimeout to go off in a second and give
- ourselves plenty of time to stop the timer. */
+ /*
+ * Set the pretimeout to go off in a second and give
+ * ourselves plenty of time to stop the timer.
+ */
ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */
pretimeout = 99;
@@ -974,7 +993,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
" occur. The NMI pretimeout will"
" likely not work\n");
}
- out_restore:
+ out_restore:
testing_nmi = 0;
preop_val = old_preop_val;
pretimeout = old_pretimeout;
@@ -1009,9 +1028,11 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
/* Make sure no one can call us any more. */
misc_deregister(&ipmi_wdog_miscdev);
- /* Wait to make sure the message makes it out. The lower layer has
- pointers to our buffers, we want to make sure they are done before
- we release our memory. */
+ /*
+ * Wait to make sure the message makes it out. The lower layer has
+ * pointers to our buffers, we want to make sure they are done before
+ * we release our memory.
+ */
while (atomic_read(&set_timeout_tofree))
schedule_timeout_uninterruptible(1);
@@ -1052,15 +1073,17 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
return NOTIFY_STOP;
}
- /* If we are not expecting a timeout, ignore it. */
+ /* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
return NOTIFY_OK;
if (preaction_val != WDOG_PRETIMEOUT_NMI)
return NOTIFY_OK;
- /* If no one else handled the NMI, we assume it was the IPMI
- watchdog. */
+ /*
+ * If no one else handled the NMI, we assume it was the IPMI
+ * watchdog.
+ */
if (preop_val == WDOG_PREOP_PANIC) {
/* On some machines, the heartbeat will give
an error and not work unless we re-enable
@@ -1082,7 +1105,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
unsigned long code,
void *unused)
{
- static int reboot_event_handled = 0;
+ static int reboot_event_handled;
if ((watchdog_user) && (!reboot_event_handled)) {
/* Make sure we only do this once. */
@@ -1115,7 +1138,7 @@ static int wdog_panic_handler(struct notifier_block *this,
unsigned long event,
void *unused)
{
- static int panic_event_handled = 0;
+ static int panic_event_handled;
/* On a panic, if we have a panic timeout, make sure to extend
the watchdog timer to a reasonable value to complete the
@@ -1125,7 +1148,7 @@ static int wdog_panic_handler(struct notifier_block *this,
ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
/* Make sure we do this only once. */
panic_event_handled = 1;
-
+
timeout = 255;
pretimeout = 0;
panic_halt_ipmi_set_timeout();
@@ -1151,8 +1174,7 @@ static void ipmi_smi_gone(int if_num)
ipmi_unregister_watchdog(if_num);
}
-static struct ipmi_smi_watcher smi_watcher =
-{
+static struct ipmi_smi_watcher smi_watcher = {
.owner = THIS_MODULE,
.new_smi = ipmi_new_smi,
.smi_gone = ipmi_smi_gone
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index eba2883b630e..4f3cefa8eb0e 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -126,8 +126,8 @@
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <linux/pci.h>
@@ -189,7 +189,7 @@ struct isi_board {
unsigned short status;
unsigned short port_status; /* each bit for each port */
unsigned short shift_count;
- struct isi_port * ports;
+ struct isi_port *ports;
signed char count;
spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
unsigned long flags;
@@ -205,11 +205,11 @@ struct isi_port {
u16 channel;
u16 status;
u16 closing_wait;
- struct isi_board * card;
- struct tty_struct * tty;
+ struct isi_board *card;
+ struct tty_struct *tty;
wait_queue_head_t close_wait;
wait_queue_head_t open_wait;
- unsigned char * xmit_buf;
+ unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
@@ -405,7 +405,7 @@ static void isicom_tx(unsigned long _data)
/* find next active board */
card = (prev_card + 1) & 0x0003;
- while(count-- > 0) {
+ while (count-- > 0) {
if (isi_card[card].status & BOARD_ACTIVE)
break;
card = (card + 1) & 0x0003;
@@ -428,7 +428,7 @@ static void isicom_tx(unsigned long _data)
if (retries >= 100)
goto unlock;
- for (;count > 0;count--, port++) {
+ for (; count > 0; count--, port++) {
/* port not active or tx disabled to force flow control */
if (!(port->flags & ASYNC_INITIALIZED) ||
!(port->status & ISI_TXOK))
@@ -471,9 +471,10 @@ static void isicom_tx(unsigned long _data)
break;
}
}
- if (cnt <= 0) break;
+ if (cnt <= 0)
+ break;
word_count = cnt >> 1;
- outsw(base, port->xmit_buf+port->xmit_tail,word_count);
+ outsw(base, port->xmit_buf+port->xmit_tail, word_count);
port->xmit_tail = (port->xmit_tail
+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
txcount -= (word_count << 1);
@@ -556,7 +557,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
tty = port->tty;
if (tty == NULL) {
word_count = byte_count >> 1;
- while(byte_count > 1) {
+ while (byte_count > 1) {
inw(base);
byte_count -= 2;
}
@@ -569,7 +570,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (header & 0x8000) { /* Status Packet */
header = inw(base);
- switch(header & 0xff) {
+ switch (header & 0xff) {
case 0: /* Change in EIA signals */
if (port->flags & ASYNC_CHECK_CD) {
if (port->status & ISI_DCD) {
@@ -656,7 +657,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
if (byte_count > 0) {
pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
"bytes...\n", base, channel + 1);
- while(byte_count > 0) { /* drain out unread xtra data */
+ /* drain out unread xtra data */
+ while (byte_count > 0) {
inw(base);
byte_count -= 2;
}
@@ -679,8 +681,11 @@ static void isicom_config_port(struct isi_port *port)
shift_count = card->shift_count;
unsigned char flow_ctrl;
- if (!(tty = port->tty) || !tty->termios)
+ tty = port->tty;
+
+ if (tty == NULL)
return;
+ /* FIXME: Switch to new tty baud API */
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
baud &= ~CBAUDEX;
@@ -706,7 +711,7 @@ static void isicom_config_port(struct isi_port *port)
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
baud++; /* 57.6 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- baud +=2; /* 115 Kbps */
+ 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)
@@ -716,15 +721,14 @@ static void isicom_config_port(struct isi_port *port)
/* hang up */
drop_dtr(port);
return;
- }
- else
+ } else
raise_dtr(port);
if (WaitTillCardIsFree(base) == 0) {
- outw(0x8000 | (channel << shift_count) |0x03, base);
+ outw(0x8000 | (channel << shift_count) | 0x03, base);
outw(linuxb_to_isib[baud] << 8 | 0x03, base);
channel_setup = 0;
- switch(C_CSIZE(tty)) {
+ switch (C_CSIZE(tty)) {
case CS5:
channel_setup |= ISICOM_CS5;
break;
@@ -767,7 +771,7 @@ static void isicom_config_port(struct isi_port *port)
flow_ctrl |= ISICOM_INITIATE_XONXOFF;
if (WaitTillCardIsFree(base) == 0) {
- outw(0x8000 | (channel << shift_count) |0x04, base);
+ outw(0x8000 | (channel << shift_count) | 0x04, base);
outw(flow_ctrl << 8 | 0x05, base);
outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
InterruptTheCard(base);
@@ -805,20 +809,17 @@ static int isicom_setup_port(struct isi_port *port)
struct isi_board *card = port->card;
unsigned long flags;
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED)
return 0;
- }
if (!port->xmit_buf) {
- unsigned long page;
-
- if (!(page = get_zeroed_page(GFP_KERNEL)))
+ /* Relies on BKL */
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ if (page == 0)
return -ENOMEM;
-
- if (port->xmit_buf) {
+ if (port->xmit_buf)
free_page(page);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) page;
+ else
+ port->xmit_buf = (unsigned char *) page;
}
spin_lock_irqsave(&card->card_lock, flags);
@@ -949,21 +950,18 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
port->count++;
tty->driver_data = port;
port->tty = tty;
- if ((error = isicom_setup_port(port))!=0)
- return error;
- if ((error = block_til_ready(tty, filp, port))!=0)
- return error;
-
- return 0;
+ error = isicom_setup_port(port);
+ if (error == 0)
+ error = block_til_ready(tty, filp, port);
+ return error;
}
/* close et all */
static inline void isicom_shutdown_board(struct isi_board *bp)
{
- if (bp->status & BOARD_ACTIVE) {
+ if (bp->status & BOARD_ACTIVE)
bp->status &= ~BOARD_ACTIVE;
- }
}
/* card->lock HAS to be held */
@@ -1012,6 +1010,22 @@ static void isicom_shutdown_port(struct isi_port *port)
}
}
+static void isicom_flush_buffer(struct tty_struct *tty)
+{
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
+ return;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&card->card_lock, flags);
+
+ tty_wakeup(tty);
+}
+
static void isicom_close(struct tty_struct *tty, struct file *filp)
{
struct isi_port *port = tty->driver_data;
@@ -1065,8 +1079,7 @@ static void isicom_close(struct tty_struct *tty, struct file *filp)
isicom_shutdown_port(port);
spin_unlock_irqrestore(&card->card_lock, flags);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ isicom_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
@@ -1104,7 +1117,7 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
spin_lock_irqsave(&card->card_lock, flags);
- while(1) {
+ while (1) {
cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
- 1, SERIAL_XMIT_SIZE - port->xmit_head));
if (cnt <= 0)
@@ -1125,28 +1138,29 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
}
/* put_char et all */
-static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
+static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
{
struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card;
unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
- return;
+ return 0;
if (!port->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&card->card_lock, flags);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
spin_unlock_irqrestore(&card->card_lock, flags);
- return;
+ return 0;
}
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt++;
spin_unlock_irqrestore(&card->card_lock, flags);
+ return 1;
}
/* flush_chars et all */
@@ -1258,6 +1272,8 @@ static int isicom_set_serial_info(struct isi_port *port,
if (copy_from_user(&newinfo, info, sizeof(newinfo)))
return -EFAULT;
+ lock_kernel();
+
reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
(newinfo.flags & ASYNC_SPD_MASK));
@@ -1265,12 +1281,13 @@ static int isicom_set_serial_info(struct isi_port *port,
if ((newinfo.close_delay != port->close_delay) ||
(newinfo.closing_wait != port->closing_wait) ||
((newinfo.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK))) {
+ unlock_kernel();
return -EPERM;
- port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
+ }
+ port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(newinfo.flags & ASYNC_USR_MASK));
- }
- else {
+ } else {
port->close_delay = newinfo.close_delay;
port->closing_wait = newinfo.closing_wait;
port->flags = ((port->flags & ~ASYNC_FLAGS) |
@@ -1282,6 +1299,7 @@ static int isicom_set_serial_info(struct isi_port *port,
isicom_config_port(port);
spin_unlock_irqrestore(&port->card->card_lock, flags);
}
+ unlock_kernel();
return 0;
}
@@ -1290,6 +1308,7 @@ static int isicom_get_serial_info(struct isi_port *port,
{
struct serial_struct out_info;
+ lock_kernel();
memset(&out_info, 0, sizeof(out_info));
/* out_info.type = ? */
out_info.line = port - isi_ports;
@@ -1299,6 +1318,7 @@ static int isicom_get_serial_info(struct isi_port *port,
/* out_info.baud_base = ? */
out_info.close_delay = port->close_delay;
out_info.closing_wait = port->closing_wait;
+ unlock_kernel();
if (copy_to_user(info, &out_info, sizeof(out_info)))
return -EFAULT;
return 0;
@@ -1314,7 +1334,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
- switch(cmd) {
+ switch (cmd) {
case TCSBRK:
retval = tty_check_change(tty);
if (retval)
@@ -1331,19 +1351,6 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
tty_wait_until_sent(tty, 0);
isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
return 0;
-
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long __user *)argp);
-
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
-
case TIOCGSERIAL:
return isicom_get_serial_info(port, argp);
@@ -1453,22 +1460,6 @@ static void isicom_hangup(struct tty_struct *tty)
wake_up_interruptible(&port->open_wait);
}
-/* flush_buffer et all */
-static void isicom_flush_buffer(struct tty_struct *tty)
-{
- struct isi_port *port = tty->driver_data;
- struct isi_board *card = port->card;
- unsigned long flags;
-
- if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
- return;
-
- spin_lock_irqsave(&card->card_lock, flags);
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&card->card_lock, flags);
-
- tty_wakeup(tty);
-}
/*
* Driver init and deinit functions
@@ -1592,7 +1583,7 @@ static int __devinit load_firmware(struct pci_dev *pdev,
default:
dev_err(&pdev->dev, "Unknown signature.\n");
goto end;
- }
+ }
retval = request_firmware(&fw, name, &pdev->dev);
if (retval)
@@ -1620,7 +1611,8 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected load header:\n"
KERN_WARNING "Address:0x%x\n"
KERN_WARNING "Count:0x%x\n"
@@ -1637,12 +1629,13 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_err(&pdev->dev, "Card%d got out of sync.Card "
"Status:0x%x\n", index + 1, status);
goto errrelfw;
}
- }
+ }
/* XXX: should we test it by reading it back and comparing with original like
* in load firmware package? */
@@ -1666,7 +1659,8 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
KERN_WARNING "Address:0x%x\n"
KERN_WARNING "Count:0x%x\n"
@@ -1699,7 +1693,8 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_err(&pdev->dev, "Card%d verify got out of sync. "
"Card Status:0x%x\n", index + 1, status);
goto errrelfw;
@@ -1764,7 +1759,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
index + 1);
retval = -EBUSY;
goto errdec;
- }
+ }
retval = request_irq(board->irq, isicom_interrupt,
IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
@@ -1818,7 +1813,7 @@ static int __init isicom_init(void)
int retval, idx, channel;
struct isi_port *port;
- for(idx = 0; idx < BOARD_COUNT; idx++) {
+ for (idx = 0; idx < BOARD_COUNT; idx++) {
port = &isi_ports[idx * 16];
isi_card[idx].ports = port;
spin_lock_init(&isi_card[idx].card_lock);
@@ -1832,7 +1827,7 @@ static int __init isicom_init(void)
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
/* . . . */
- }
+ }
isi_card[idx].base = 0;
isi_card[idx].irq = 0;
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index c645455c3fd1..7c8b62f162bf 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -1682,16 +1682,6 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
rc = 0;
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) arg);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *) arg)) == 0)
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stli_getserial(portp, argp);
break;
@@ -3267,7 +3257,7 @@ static int stli_initecp(struct stlibrd *brdp)
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL) {
retval = -ENOMEM;
goto err_reg;
@@ -3424,7 +3414,7 @@ static int stli_initonb(struct stlibrd *brdp)
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL) {
retval = -ENOMEM;
goto err_reg;
@@ -3675,7 +3665,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp)
*/
for (i = 0; (i < stli_eisamempsize); i++) {
brdp->memaddr = stli_eisamemprobeaddrs[i];
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL)
continue;
@@ -4433,6 +4423,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
done = 0;
rc = 0;
+ lock_kernel();
+
switch (cmd) {
case COM_GETPORTSTATS:
rc = stli_getportstats(NULL, argp);
@@ -4455,6 +4447,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
done++;
break;
}
+ unlock_kernel();
if (done)
return rc;
@@ -4472,6 +4465,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
if (brdp->state == 0)
return -ENODEV;
+ lock_kernel();
+
switch (cmd) {
case STL_BINTR:
EBRDINTR(brdp);
@@ -4494,6 +4489,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 60b934adea65..7f7e798c1384 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -110,6 +110,7 @@ const int max_vals[] = {
const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@ void kd_mksound(unsigned int hz, unsigned int ticks)
} else
kd_nosound(0);
}
+EXPORT_SYMBOL(kd_mksound);
/*
* Setting the keyboard rate.
@@ -1230,7 +1232,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
- (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) {
+ (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
/*
* Don't repeat a key if the input buffers are not empty and the
* characters get aren't echoed locally. This makes key repeat
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e83623ead441..934ffafedaea 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -364,6 +364,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
return 0;
}
+#ifdef CONFIG_DEVKMEM
static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
{
unsigned long pfn;
@@ -384,6 +385,7 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
vma->vm_pgoff = pfn;
return mmap_mem(file, vma);
}
+#endif
#ifdef CONFIG_CRASH_DUMP
/*
@@ -422,6 +424,7 @@ static ssize_t read_oldmem(struct file *file, char __user *buf,
extern long vread(char *buf, char *addr, unsigned long count);
extern long vwrite(char *buf, char *addr, unsigned long count);
+#ifdef CONFIG_DEVKMEM
/*
* This function reads the *virtual* memory as seen by the kernel.
*/
@@ -626,6 +629,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
*ppos = p;
return virtr + wrote;
}
+#endif
#ifdef CONFIG_DEVPORT
static ssize_t read_port(struct file * file, char __user * buf,
@@ -803,6 +807,7 @@ static const struct file_operations mem_fops = {
.get_unmapped_area = get_unmapped_area_mem,
};
+#ifdef CONFIG_DEVKMEM
static const struct file_operations kmem_fops = {
.llseek = memory_lseek,
.read = read_kmem,
@@ -811,6 +816,7 @@ static const struct file_operations kmem_fops = {
.open = open_kmem,
.get_unmapped_area = get_unmapped_area_mem,
};
+#endif
static const struct file_operations null_fops = {
.llseek = null_lseek,
@@ -889,11 +895,13 @@ static int memory_open(struct inode * inode, struct file * filp)
filp->f_mapping->backing_dev_info =
&directly_mappable_cdev_bdi;
break;
+#ifdef CONFIG_DEVKMEM
case 2:
filp->f_op = &kmem_fops;
filp->f_mapping->backing_dev_info =
&directly_mappable_cdev_bdi;
break;
+#endif
case 3:
filp->f_op = &null_fops;
break;
@@ -942,7 +950,9 @@ static const struct {
const struct file_operations *fops;
} devlist[] = { /* list of minor devices */
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
+#ifdef CONFIG_DEVKMEM
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
+#endif
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
#ifdef CONFIG_DEVPORT
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 4d058dadbfcc..eaace0db0ff4 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -263,23 +263,26 @@ EXPORT_SYMBOL(misc_deregister);
static int __init misc_init(void)
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
+ int err;
- ent = create_proc_entry("misc", 0, NULL);
- if (ent)
- ent->proc_fops = &misc_proc_fops;
+#ifdef CONFIG_PROC_FS
+ proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
misc_class = class_create(THIS_MODULE, "misc");
+ err = PTR_ERR(misc_class);
if (IS_ERR(misc_class))
- return PTR_ERR(misc_class);
+ goto fail_remove;
- if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
- printk("unable to get major %d for misc devices\n",
- MISC_MAJOR);
- class_destroy(misc_class);
- return -EIO;
- }
+ err = -EIO;
+ if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
+ goto fail_printk;
return 0;
+
+fail_printk:
+ printk("unable to get major %d for misc devices\n", MISC_MAJOR);
+ class_destroy(misc_class);
+fail_remove:
+ remove_proc_entry("misc", NULL);
+ return err;
}
subsys_initcall(misc_init);
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index e60a74c66e3d..192961fd7173 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -30,6 +30,8 @@
#include <linux/miscdevice.h>
#include <linux/posix-timers.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/math64.h>
#include <asm/uaccess.h>
#include <asm/sn/addrs.h>
@@ -74,9 +76,8 @@ static const struct file_operations mmtimer_fops = {
* We only have comparison registers RTC1-4 currently available per
* node. RTC0 is used by SAL.
*/
-#define NUM_COMPARATORS 3
/* Check for an RTC interrupt pending */
-static int inline mmtimer_int_pending(int comparator)
+static int mmtimer_int_pending(int comparator)
{
if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) &
SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator)
@@ -84,15 +85,16 @@ static int inline mmtimer_int_pending(int comparator)
else
return 0;
}
+
/* Clear the RTC interrupt pending bit */
-static void inline mmtimer_clr_int_pending(int comparator)
+static void mmtimer_clr_int_pending(int comparator)
{
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator);
}
/* Setup timer on comparator RTC1 */
-static void inline mmtimer_setup_int_0(u64 expires)
+static void mmtimer_setup_int_0(int cpu, u64 expires)
{
u64 val;
@@ -106,7 +108,7 @@ static void inline mmtimer_setup_int_0(u64 expires)
mmtimer_clr_int_pending(0);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC1_INT_CONFIG_PID_SHFT);
/* Set configuration */
@@ -122,7 +124,7 @@ static void inline mmtimer_setup_int_0(u64 expires)
}
/* Setup timer on comparator RTC2 */
-static void inline mmtimer_setup_int_1(u64 expires)
+static void mmtimer_setup_int_1(int cpu, u64 expires)
{
u64 val;
@@ -133,7 +135,7 @@ static void inline mmtimer_setup_int_1(u64 expires)
mmtimer_clr_int_pending(1);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC2_INT_CONFIG_PID_SHFT);
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val);
@@ -144,7 +146,7 @@ static void inline mmtimer_setup_int_1(u64 expires)
}
/* Setup timer on comparator RTC3 */
-static void inline mmtimer_setup_int_2(u64 expires)
+static void mmtimer_setup_int_2(int cpu, u64 expires)
{
u64 val;
@@ -155,7 +157,7 @@ static void inline mmtimer_setup_int_2(u64 expires)
mmtimer_clr_int_pending(2);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC3_INT_CONFIG_PID_SHFT);
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val);
@@ -170,22 +172,22 @@ static void inline mmtimer_setup_int_2(u64 expires)
* in order to insure that the setup succeeds in a deterministic time frame.
* It will check if the interrupt setup succeeded.
*/
-static int inline mmtimer_setup(int comparator, unsigned long expires)
+static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
{
switch (comparator) {
case 0:
- mmtimer_setup_int_0(expires);
+ mmtimer_setup_int_0(cpu, expires);
break;
case 1:
- mmtimer_setup_int_1(expires);
+ mmtimer_setup_int_1(cpu, expires);
break;
case 2:
- mmtimer_setup_int_2(expires);
+ mmtimer_setup_int_2(cpu, expires);
break;
}
/* We might've missed our expiration time */
- if (rtc_time() < expires)
+ if (rtc_time() <= expires)
return 1;
/*
@@ -195,7 +197,7 @@ static int inline mmtimer_setup(int comparator, unsigned long expires)
return mmtimer_int_pending(comparator);
}
-static int inline mmtimer_disable_int(long nasid, int comparator)
+static int mmtimer_disable_int(long nasid, int comparator)
{
switch (comparator) {
case 0:
@@ -216,18 +218,124 @@ static int inline mmtimer_disable_int(long nasid, int comparator)
return 0;
}
-#define TIMER_OFF 0xbadcabLL
+#define COMPARATOR 1 /* The comparator to use */
-/* There is one of these for each comparator */
-typedef struct mmtimer {
- spinlock_t lock ____cacheline_aligned;
+#define TIMER_OFF 0xbadcabLL /* Timer is not setup */
+#define TIMER_SET 0 /* Comparator is set for this timer */
+
+/* There is one of these for each timer */
+struct mmtimer {
+ struct rb_node list;
struct k_itimer *timer;
- int i;
int cpu;
+};
+
+struct mmtimer_node {
+ spinlock_t lock ____cacheline_aligned;
+ struct rb_root timer_head;
+ struct rb_node *next;
struct tasklet_struct tasklet;
-} mmtimer_t;
+};
+static struct mmtimer_node *timers;
+
+
+/*
+ * Add a new mmtimer struct to the node's mmtimer list.
+ * This function assumes the struct mmtimer_node is locked.
+ */
+static void mmtimer_add_list(struct mmtimer *n)
+{
+ int nodeid = n->timer->it.mmtimer.node;
+ unsigned long expires = n->timer->it.mmtimer.expires;
+ struct rb_node **link = &timers[nodeid].timer_head.rb_node;
+ struct rb_node *parent = NULL;
+ struct mmtimer *x;
+
+ /*
+ * Find the right place in the rbtree:
+ */
+ while (*link) {
+ parent = *link;
+ x = rb_entry(parent, struct mmtimer, list);
+
+ if (expires < x->timer->it.mmtimer.expires)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+
+ /*
+ * Insert the timer to the rbtree and check whether it
+ * replaces the first pending timer
+ */
+ rb_link_node(&n->list, parent, link);
+ rb_insert_color(&n->list, &timers[nodeid].timer_head);
+
+ if (!timers[nodeid].next || expires < rb_entry(timers[nodeid].next,
+ struct mmtimer, list)->timer->it.mmtimer.expires)
+ timers[nodeid].next = &n->list;
+}
+
+/*
+ * Set the comparator for the next timer.
+ * This function assumes the struct mmtimer_node is locked.
+ */
+static void mmtimer_set_next_timer(int nodeid)
+{
+ struct mmtimer_node *n = &timers[nodeid];
+ struct mmtimer *x;
+ struct k_itimer *t;
+ int o;
+
+restart:
+ if (n->next == NULL)
+ return;
-static mmtimer_t ** timers;
+ x = rb_entry(n->next, struct mmtimer, list);
+ t = x->timer;
+ if (!t->it.mmtimer.incr) {
+ /* Not an interval timer */
+ if (!mmtimer_setup(x->cpu, COMPARATOR,
+ t->it.mmtimer.expires)) {
+ /* Late setup, fire now */
+ tasklet_schedule(&n->tasklet);
+ }
+ return;
+ }
+
+ /* Interval timer */
+ o = 0;
+ while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) {
+ unsigned long e, e1;
+ struct rb_node *next;
+ t->it.mmtimer.expires += t->it.mmtimer.incr << o;
+ t->it_overrun += 1 << o;
+ o++;
+ if (o > 20) {
+ printk(KERN_ALERT "mmtimer: cannot reschedule timer\n");
+ t->it.mmtimer.clock = TIMER_OFF;
+ n->next = rb_next(&x->list);
+ rb_erase(&x->list, &n->timer_head);
+ kfree(x);
+ goto restart;
+ }
+
+ e = t->it.mmtimer.expires;
+ next = rb_next(&x->list);
+
+ if (next == NULL)
+ continue;
+
+ e1 = rb_entry(next, struct mmtimer, list)->
+ timer->it.mmtimer.expires;
+ if (e > e1) {
+ n->next = next;
+ rb_erase(&x->list, &n->timer_head);
+ mmtimer_add_list(x);
+ goto restart;
+ }
+ }
+}
/**
* mmtimer_ioctl - ioctl interface for /dev/mmtimer
@@ -366,8 +474,8 @@ static int sgi_clock_get(clockid_t clockid, struct timespec *tp)
nsec = rtc_time() * sgi_clock_period
+ sgi_clock_offset.tv_nsec;
- tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec)
- + sgi_clock_offset.tv_sec;
+ *tp = ns_to_timespec(nsec);
+ tp->tv_sec += sgi_clock_offset.tv_sec;
return 0;
};
@@ -375,11 +483,11 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
{
u64 nsec;
- u64 rem;
+ u32 rem;
nsec = rtc_time() * sgi_clock_period;
- sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ sgi_clock_offset.tv_sec = tp->tv_sec - div_u64_rem(nsec, NSEC_PER_SEC, &rem);
if (rem <= tp->tv_nsec)
sgi_clock_offset.tv_nsec = tp->tv_sec - rem;
@@ -390,35 +498,6 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
return 0;
}
-/*
- * Schedule the next periodic interrupt. This function will attempt
- * to schedule a periodic interrupt later if necessary. If the scheduling
- * of an interrupt fails then the time to skip is lengthened
- * exponentially in order to ensure that the next interrupt
- * can be properly scheduled..
- */
-static int inline reschedule_periodic_timer(mmtimer_t *x)
-{
- int n;
- struct k_itimer *t = x->timer;
-
- t->it.mmtimer.clock = x->i;
- t->it_overrun--;
-
- n = 0;
- do {
-
- t->it.mmtimer.expires += t->it.mmtimer.incr << n;
- t->it_overrun += 1 << n;
- n++;
- if (n > 20)
- return 1;
-
- } while (!mmtimer_setup(x->i, t->it.mmtimer.expires));
-
- return 0;
-}
-
/**
* mmtimer_interrupt - timer interrupt handler
* @irq: irq received
@@ -435,71 +514,75 @@ static int inline reschedule_periodic_timer(mmtimer_t *x)
static irqreturn_t
mmtimer_interrupt(int irq, void *dev_id)
{
- int i;
unsigned long expires = 0;
int result = IRQ_NONE;
unsigned indx = cpu_to_node(smp_processor_id());
+ struct mmtimer *base;
- /*
- * Do this once for each comparison register
- */
- for (i = 0; i < NUM_COMPARATORS; i++) {
- mmtimer_t *base = timers[indx] + i;
- /* Make sure this doesn't get reused before tasklet_sched */
- spin_lock(&base->lock);
- if (base->cpu == smp_processor_id()) {
- if (base->timer)
- expires = base->timer->it.mmtimer.expires;
- /* expires test won't work with shared irqs */
- if ((mmtimer_int_pending(i) > 0) ||
- (expires && (expires < rtc_time()))) {
- mmtimer_clr_int_pending(i);
- tasklet_schedule(&base->tasklet);
- result = IRQ_HANDLED;
- }
+ spin_lock(&timers[indx].lock);
+ base = rb_entry(timers[indx].next, struct mmtimer, list);
+ if (base == NULL) {
+ spin_unlock(&timers[indx].lock);
+ return result;
+ }
+
+ if (base->cpu == smp_processor_id()) {
+ if (base->timer)
+ expires = base->timer->it.mmtimer.expires;
+ /* expires test won't work with shared irqs */
+ if ((mmtimer_int_pending(COMPARATOR) > 0) ||
+ (expires && (expires <= rtc_time()))) {
+ mmtimer_clr_int_pending(COMPARATOR);
+ tasklet_schedule(&timers[indx].tasklet);
+ result = IRQ_HANDLED;
}
- spin_unlock(&base->lock);
- expires = 0;
}
+ spin_unlock(&timers[indx].lock);
return result;
}
-void mmtimer_tasklet(unsigned long data) {
- mmtimer_t *x = (mmtimer_t *)data;
- struct k_itimer *t = x->timer;
+static void mmtimer_tasklet(unsigned long data)
+{
+ int nodeid = data;
+ struct mmtimer_node *mn = &timers[nodeid];
+ struct mmtimer *x = rb_entry(mn->next, struct mmtimer, list);
+ struct k_itimer *t;
unsigned long flags;
- if (t == NULL)
- return;
-
/* Send signal and deal with periodic signals */
- spin_lock_irqsave(&t->it_lock, flags);
- spin_lock(&x->lock);
- /* If timer was deleted between interrupt and here, leave */
- if (t != x->timer)
+ spin_lock_irqsave(&mn->lock, flags);
+ if (!mn->next)
goto out;
- t->it_overrun = 0;
- if (posix_timer_event(t, 0) != 0) {
+ x = rb_entry(mn->next, struct mmtimer, list);
+ t = x->timer;
+
+ if (t->it.mmtimer.clock == TIMER_OFF)
+ goto out;
+
+ t->it_overrun = 0;
- // printk(KERN_WARNING "mmtimer: cannot deliver signal.\n");
+ mn->next = rb_next(&x->list);
+ rb_erase(&x->list, &mn->timer_head);
+ if (posix_timer_event(t, 0) != 0)
t->it_overrun++;
- }
+
if(t->it.mmtimer.incr) {
- /* Periodic timer */
- if (reschedule_periodic_timer(x)) {
- printk(KERN_WARNING "mmtimer: unable to reschedule\n");
- x->timer = NULL;
- }
+ t->it.mmtimer.expires += t->it.mmtimer.incr;
+ mmtimer_add_list(x);
} else {
/* Ensure we don't false trigger in mmtimer_interrupt */
+ t->it.mmtimer.clock = TIMER_OFF;
t->it.mmtimer.expires = 0;
+ kfree(x);
}
+ /* Set comparator for next timer, if there is one */
+ mmtimer_set_next_timer(nodeid);
+
t->it_overrun_last = t->it_overrun;
out:
- spin_unlock(&x->lock);
- spin_unlock_irqrestore(&t->it_lock, flags);
+ spin_unlock_irqrestore(&mn->lock, flags);
}
static int sgi_timer_create(struct k_itimer *timer)
@@ -516,25 +599,53 @@ static int sgi_timer_create(struct k_itimer *timer)
*/
static int sgi_timer_del(struct k_itimer *timr)
{
- int i = timr->it.mmtimer.clock;
cnodeid_t nodeid = timr->it.mmtimer.node;
- mmtimer_t *t = timers[nodeid] + i;
unsigned long irqflags;
- if (i != TIMER_OFF) {
- spin_lock_irqsave(&t->lock, irqflags);
- mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
- t->timer = NULL;
+ spin_lock_irqsave(&timers[nodeid].lock, irqflags);
+ if (timr->it.mmtimer.clock != TIMER_OFF) {
+ unsigned long expires = timr->it.mmtimer.expires;
+ struct rb_node *n = timers[nodeid].timer_head.rb_node;
+ struct mmtimer *uninitialized_var(t);
+ int r = 0;
+
timr->it.mmtimer.clock = TIMER_OFF;
timr->it.mmtimer.expires = 0;
- spin_unlock_irqrestore(&t->lock, irqflags);
+
+ while (n) {
+ t = rb_entry(n, struct mmtimer, list);
+ if (t->timer == timr)
+ break;
+
+ if (expires < t->timer->it.mmtimer.expires)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+
+ if (!n) {
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
+ return 0;
+ }
+
+ if (timers[nodeid].next == n) {
+ timers[nodeid].next = rb_next(n);
+ r = 1;
+ }
+
+ rb_erase(n, &timers[nodeid].timer_head);
+ kfree(t);
+
+ if (r) {
+ mmtimer_disable_int(cnodeid_to_nasid(nodeid),
+ COMPARATOR);
+ mmtimer_set_next_timer(nodeid);
+ }
}
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
return 0;
}
-#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC)
-#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec)
-
/* Assumption: it_lock is already held with irq's disabled */
static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
{
@@ -547,9 +658,8 @@ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
return;
}
- ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
- ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
- return;
+ cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period);
+ cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period);
}
@@ -557,30 +667,33 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
struct itimerspec * new_setting,
struct itimerspec * old_setting)
{
-
- int i;
unsigned long when, period, irqflags;
int err = 0;
cnodeid_t nodeid;
- mmtimer_t *base;
+ struct mmtimer *base;
+ struct rb_node *n;
if (old_setting)
sgi_timer_get(timr, old_setting);
sgi_timer_del(timr);
- when = timespec_to_ns(new_setting->it_value);
- period = timespec_to_ns(new_setting->it_interval);
+ when = timespec_to_ns(&new_setting->it_value);
+ period = timespec_to_ns(&new_setting->it_interval);
if (when == 0)
/* Clear timer */
return 0;
+ base = kmalloc(sizeof(struct mmtimer), GFP_KERNEL);
+ if (base == NULL)
+ return -ENOMEM;
+
if (flags & TIMER_ABSTIME) {
struct timespec n;
unsigned long now;
getnstimeofday(&n);
- now = timespec_to_ns(n);
+ now = timespec_to_ns(&n);
if (when > now)
when -= now;
else
@@ -604,47 +717,38 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
preempt_disable();
nodeid = cpu_to_node(smp_processor_id());
-retry:
- /* Don't use an allocated timer, or a deleted one that's pending */
- for(i = 0; i< NUM_COMPARATORS; i++) {
- base = timers[nodeid] + i;
- if (!base->timer && !base->tasklet.state) {
- break;
- }
- }
-
- if (i == NUM_COMPARATORS) {
- preempt_enable();
- return -EBUSY;
- }
- spin_lock_irqsave(&base->lock, irqflags);
+ /* Lock the node timer structure */
+ spin_lock_irqsave(&timers[nodeid].lock, irqflags);
- if (base->timer || base->tasklet.state != 0) {
- spin_unlock_irqrestore(&base->lock, irqflags);
- goto retry;
- }
base->timer = timr;
base->cpu = smp_processor_id();
- timr->it.mmtimer.clock = i;
+ timr->it.mmtimer.clock = TIMER_SET;
timr->it.mmtimer.node = nodeid;
timr->it.mmtimer.incr = period;
timr->it.mmtimer.expires = when;
- if (period == 0) {
- if (!mmtimer_setup(i, when)) {
- mmtimer_disable_int(-1, i);
- posix_timer_event(timr, 0);
- timr->it.mmtimer.expires = 0;
- }
- } else {
- timr->it.mmtimer.expires -= period;
- if (reschedule_periodic_timer(base))
- err = -EINVAL;
+ n = timers[nodeid].next;
+
+ /* Add the new struct mmtimer to node's timer list */
+ mmtimer_add_list(base);
+
+ if (timers[nodeid].next == n) {
+ /* No need to reprogram comparator for now */
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
+ preempt_enable();
+ return err;
}
- spin_unlock_irqrestore(&base->lock, irqflags);
+ /* We need to reprogram the comparator */
+ if (n)
+ mmtimer_disable_int(cnodeid_to_nasid(nodeid), COMPARATOR);
+
+ mmtimer_set_next_timer(nodeid);
+
+ /* Unlock the node timer structure */
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
preempt_enable();
@@ -669,7 +773,6 @@ static struct k_clock sgi_clock = {
*/
static int __init mmtimer_init(void)
{
- unsigned i;
cnodeid_t node, maxn = -1;
if (!ia64_platform_is("sn2"))
@@ -706,31 +809,18 @@ static int __init mmtimer_init(void)
maxn++;
/* Allocate list of node ptrs to mmtimer_t's */
- timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+ timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL);
if (timers == NULL) {
printk(KERN_ERR "%s: failed to allocate memory for device\n",
MMTIMER_NAME);
goto out3;
}
- /* Allocate mmtimer_t's for each online node */
+ /* Initialize struct mmtimer's for each online node */
for_each_online_node(node) {
- timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
- if (timers[node] == NULL) {
- printk(KERN_ERR "%s: failed to allocate memory for device\n",
- MMTIMER_NAME);
- goto out4;
- }
- for (i=0; i< NUM_COMPARATORS; i++) {
- mmtimer_t * base = timers[node] + i;
-
- spin_lock_init(&base->lock);
- base->timer = NULL;
- base->cpu = 0;
- base->i = i;
- tasklet_init(&base->tasklet, mmtimer_tasklet,
- (unsigned long) (base));
- }
+ spin_lock_init(&timers[node].lock);
+ tasklet_init(&timers[node].tasklet, mmtimer_tasklet,
+ (unsigned long) node);
}
sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
@@ -741,11 +831,8 @@ static int __init mmtimer_init(void)
return 0;
-out4:
- for_each_online_node(node) {
- kfree(timers[node]);
- }
out3:
+ kfree(timers);
misc_deregister(&mmtimer_miscdev);
out2:
free_irq(SGI_MMTIMER_VECTOR, NULL);
@@ -754,4 +841,3 @@ out1:
}
module_init(mmtimer_init);
-
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 64b7b2b18352..d57d3a61919b 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -2,7 +2,8 @@
/*
* moxa.c -- MOXA Intellio family multiport serial driver.
*
- * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com).
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
@@ -25,6 +26,7 @@
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/errno.h>
+#include <linux/firmware.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
@@ -41,21 +43,26 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>
-#include <linux/completion.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#define MOXA_VERSION "5.1k"
+#include "moxa.h"
+
+#define MOXA_VERSION "6.0k"
+
+#define MOXA_FW_HDRLEN 32
#define MOXAMAJOR 172
-#define MOXACUMAJOR 173
#define MAX_BOARDS 4 /* Don't change this value */
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
+#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
+ (brd)->boardType == MOXA_BOARD_C320_PCI)
+
/*
* Define the Moxa PCI vendor and device IDs.
*/
@@ -92,24 +99,16 @@ static struct pci_device_id moxa_pcibrds[] = {
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
#endif /* CONFIG_PCI */
-struct moxa_isa_board_conf {
- int boardType;
- int numPorts;
- unsigned long baseAddr;
-};
-
-static struct moxa_isa_board_conf moxa_isa_boards[] =
-{
-/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */
-};
+struct moxa_port;
static struct moxa_board_conf {
int boardType;
int numPorts;
- unsigned long baseAddr;
int busType;
- int loadstat;
+ unsigned int ready;
+
+ struct moxa_port *ports;
void __iomem *basemem;
void __iomem *intNdx;
@@ -131,30 +130,27 @@ struct moxaq_str {
};
struct moxa_port {
+ struct moxa_board_conf *board;
+ struct tty_struct *tty;
+ void __iomem *tableAddr;
+
int type;
- int port;
int close_delay;
- unsigned short closing_wait;
- int count;
- int blocked_open;
- long event; /* long req'd for set_bit --RR */
+ unsigned int count;
int asyncflags;
- unsigned long statusflags;
- struct tty_struct *tty;
int cflag;
+ unsigned long statusflags;
wait_queue_head_t open_wait;
- struct completion close_wait;
-
- struct timer_list emptyTimer;
- char chkPort;
- char lineCtrl;
- void __iomem *tableAddr;
- long curBaud;
- char DCDState;
- char lowChkFlag;
+ u8 DCDState;
+ u8 lineCtrl;
+ u8 lowChkFlag;
+};
- ushort breakCnt;
+struct mon_str {
+ int tick;
+ int rxcnt[MAX_PORTS];
+ int txcnt[MAX_PORTS];
};
/* statusflags */
@@ -168,20 +164,27 @@ struct moxa_port {
#define WAKEUP_CHARS 256
static int ttymajor = MOXAMAJOR;
+static struct mon_str moxaLog;
+static unsigned int moxaFuncTout = HZ / 2;
+static unsigned int moxaLowWaterChk;
+static DEFINE_MUTEX(moxa_openlock);
/* Variables for insmod */
#ifdef MODULE
-static int baseaddr[4];
-static int type[4];
-static int numports[4];
+static unsigned long baseaddr[MAX_BOARDS];
+static unsigned int type[MAX_BOARDS];
+static unsigned int numports[MAX_BOARDS];
#endif
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
#ifdef MODULE
-module_param_array(type, int, NULL, 0);
-module_param_array(baseaddr, int, NULL, 0);
-module_param_array(numports, int, NULL, 0);
+module_param_array(type, uint, NULL, 0);
+MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
+module_param_array(baseaddr, ulong, NULL, 0);
+MODULE_PARM_DESC(baseaddr, "base address");
+module_param_array(numports, uint, NULL, 0);
+MODULE_PARM_DESC(numports, "numports (ignored for C218)");
#endif
module_param(ttymajor, int, 0);
@@ -194,9 +197,6 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int);
static int moxa_write_room(struct tty_struct *);
static void moxa_flush_buffer(struct tty_struct *);
static int moxa_chars_in_buffer(struct tty_struct *);
-static void moxa_flush_chars(struct tty_struct *);
-static void moxa_put_char(struct tty_struct *, unsigned char);
-static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
static void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
@@ -208,44 +208,183 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static void moxa_poll(unsigned long);
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
-static int moxa_block_till_ready(struct tty_struct *, struct file *,
- struct moxa_port *);
static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_check_xmit_empty(unsigned long);
static void moxa_shut_down(struct moxa_port *);
-static void moxa_receive_data(struct moxa_port *);
/*
* moxa board interface functions:
*/
-static void MoxaDriverInit(void);
-static int MoxaDriverIoctl(unsigned int, unsigned long, int);
-static int MoxaDriverPoll(void);
-static int MoxaPortsOfCard(int);
-static int MoxaPortIsValid(int);
-static void MoxaPortEnable(int);
-static void MoxaPortDisable(int);
-static long MoxaPortGetMaxBaud(int);
-static long MoxaPortSetBaud(int, long);
-static int MoxaPortSetTermio(int, struct ktermios *, speed_t);
-static int MoxaPortGetLineOut(int, int *, int *);
-static void MoxaPortLineCtrl(int, int, int);
-static void MoxaPortFlowCtrl(int, int, int, int, int, int);
-static int MoxaPortLineStatus(int);
-static int MoxaPortDCDChange(int);
-static int MoxaPortDCDON(int);
-static void MoxaPortFlushData(int, int);
-static int MoxaPortWriteData(int, unsigned char *, int);
-static int MoxaPortReadData(int, struct tty_struct *tty);
-static int MoxaPortTxQueue(int);
-static int MoxaPortRxQueue(int);
-static int MoxaPortTxFree(int);
-static void MoxaPortTxDisable(int);
-static void MoxaPortTxEnable(int);
-static int MoxaPortResetBrkCnt(int);
-static void MoxaPortSendBreak(int, int);
+static void MoxaPortEnable(struct moxa_port *);
+static void MoxaPortDisable(struct moxa_port *);
+static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
+static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
+static void MoxaPortLineCtrl(struct moxa_port *, int, int);
+static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
+static int MoxaPortLineStatus(struct moxa_port *);
+static void MoxaPortFlushData(struct moxa_port *, int);
+static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortReadData(struct moxa_port *);
+static int MoxaPortTxQueue(struct moxa_port *);
+static int MoxaPortRxQueue(struct moxa_port *);
+static int MoxaPortTxFree(struct moxa_port *);
+static void MoxaPortTxDisable(struct moxa_port *);
+static void MoxaPortTxEnable(struct moxa_port *);
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 void MoxaSetFifo(struct moxa_port *port, int enable);
+
+/*
+ * I/O functions
+ */
+
+static void moxa_wait_finish(void __iomem *ofsAddr)
+{
+ unsigned long end = jiffies + moxaFuncTout;
+
+ while (readw(ofsAddr + FuncCode) != 0)
+ if (time_after(jiffies, end))
+ return;
+ if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit())
+ printk(KERN_WARNING "moxa function expired\n");
+}
+
+static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
+{
+ writew(arg, ofsAddr + FuncArg);
+ writew(cmd, ofsAddr + FuncCode);
+ moxa_wait_finish(ofsAddr);
+}
+
+static void moxa_low_water_check(void __iomem *ofsAddr)
+{
+ u16 rptr, wptr, mask, len;
+
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
+ rptr = readw(ofsAddr + RXrptr);
+ wptr = readw(ofsAddr + RXwptr);
+ mask = readw(ofsAddr + RX_mask);
+ len = (wptr - rptr) & mask;
+ if (len <= Low_water)
+ moxafunc(ofsAddr, FC_SendXon, 0);
+ }
+}
+
+/*
+ * TTY operations
+ */
+
+static int moxa_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moxa_port *ch = tty->driver_data;
+ void __user *argp = (void __user *)arg;
+ int status, ret = 0;
+
+ if (tty->index == MAX_PORTS) {
+ if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
+ cmd != MOXA_GETMSTATUS)
+ return -EINVAL;
+ } else if (!ch)
+ return -ENODEV;
+
+ switch (cmd) {
+ case MOXA_GETDATACOUNT:
+ moxaLog.tick = jiffies;
+ if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
+ ret = -EFAULT;
+ break;
+ case MOXA_FLUSH_QUEUE:
+ MoxaPortFlushData(ch, arg);
+ break;
+ case MOXA_GET_IOQUEUE: {
+ struct moxaq_str __user *argm = argp;
+ struct moxaq_str tmp;
+ struct moxa_port *p;
+ unsigned int i, j;
+
+ mutex_lock(&moxa_openlock);
+ for (i = 0; i < MAX_BOARDS; i++) {
+ p = moxa_boards[i].ports;
+ for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (moxa_boards[i].ready) {
+ tmp.inq = MoxaPortRxQueue(p);
+ tmp.outq = MoxaPortTxQueue(p);
+ }
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
+ return -EFAULT;
+ }
+ }
+ }
+ mutex_unlock(&moxa_openlock);
+ break;
+ } case MOXA_GET_OQUEUE:
+ status = MoxaPortTxQueue(ch);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
+ case MOXA_GET_IQUEUE:
+ status = MoxaPortRxQueue(ch);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
+ case MOXA_GETMSTATUS: {
+ struct mxser_mstatus __user *argm = argp;
+ struct mxser_mstatus tmp;
+ struct moxa_port *p;
+ unsigned int i, j;
+
+ mutex_lock(&moxa_openlock);
+ for (i = 0; i < MAX_BOARDS; i++) {
+ p = moxa_boards[i].ports;
+ for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (!moxa_boards[i].ready)
+ goto copy;
+
+ status = MoxaPortLineStatus(p);
+ if (status & 1)
+ tmp.cts = 1;
+ if (status & 2)
+ tmp.dsr = 1;
+ if (status & 4)
+ tmp.dcd = 1;
+
+ if (!p->tty || !p->tty->termios)
+ tmp.cflag = p->cflag;
+ else
+ tmp.cflag = p->tty->termios->c_cflag;
+copy:
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
+ return -EFAULT;
+ }
+ }
+ }
+ mutex_unlock(&moxa_openlock);
+ break;
+ }
+ case TIOCGSERIAL:
+ mutex_lock(&moxa_openlock);
+ ret = moxa_get_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ case TIOCSSERIAL:
+ mutex_lock(&moxa_openlock);
+ ret = moxa_set_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+ return ret;
+}
+
+static void moxa_break_ctl(struct tty_struct *tty, int state)
+{
+ struct moxa_port *port = tty->driver_data;
+
+ moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
+ Magic_code);
+}
static const struct tty_operations moxa_ops = {
.open = moxa_open,
@@ -254,8 +393,6 @@ static const struct tty_operations moxa_ops = {
.write_room = moxa_write_room,
.flush_buffer = moxa_flush_buffer,
.chars_in_buffer = moxa_chars_in_buffer,
- .flush_chars = moxa_flush_chars,
- .put_char = moxa_put_char,
.ioctl = moxa_ioctl,
.throttle = moxa_throttle,
.unthrottle = moxa_unthrottle,
@@ -263,15 +400,509 @@ static const struct tty_operations moxa_ops = {
.stop = moxa_stop,
.start = moxa_start,
.hangup = moxa_hangup,
+ .break_ctl = moxa_break_ctl,
.tiocmget = moxa_tiocmget,
.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);
+/*
+ * HW init
+ */
+
+static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
+{
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ if (model != 1)
+ goto err;
+ break;
+ case MOXA_BOARD_CP204J:
+ if (model != 3)
+ goto err;
+ break;
+ default:
+ if (model != 2)
+ goto err;
+ break;
+ }
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static int moxa_check_fw(const void *ptr)
+{
+ const __le16 *lptr = ptr;
+
+ if (*lptr != cpu_to_le16(0x7980))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+ u16 tmp;
+
+ writeb(HW_reset, baseAddr + Control_reg); /* reset */
+ msleep(10);
+ memset_io(baseAddr, 0, 4096);
+ memcpy_toio(baseAddr, buf, len); /* download BIOS */
+ writeb(0, baseAddr + Control_reg); /* restart */
+
+ msleep(2000);
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ tmp = readw(baseAddr + C218_key);
+ if (tmp != C218_KeyCode)
+ goto err;
+ break;
+ case MOXA_BOARD_CP204J:
+ tmp = readw(baseAddr + C218_key);
+ if (tmp != CP204J_KeyCode)
+ goto err;
+ break;
+ default:
+ tmp = readw(baseAddr + C320_key);
+ if (tmp != C320_KeyCode)
+ goto err;
+ tmp = readw(baseAddr + C320_status);
+ if (tmp != STS_init) {
+ printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
+ "module not found\n");
+ return -EIO;
+ }
+ break;
+ }
+
+ return 0;
+err:
+ printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
+ return -EIO;
+}
+
+static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+
+ if (len < 7168) {
+ printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
+ return -EINVAL;
+ }
+
+ writew(len - 7168 - 2, baseAddr + C320bapi_len);
+ writeb(1, baseAddr + Control_reg); /* Select Page 1 */
+ memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
+ writeb(2, baseAddr + Control_reg); /* Select Page 2 */
+ memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
+
+ return 0;
+}
+
+static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+ const u16 *uptr = ptr;
+ size_t wlen, len2, j;
+ unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
+ unsigned int i, retry;
+ u16 usum, keycode;
+
+ keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
+ C218_KeyCode;
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_CP204J:
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ key = C218_key;
+ loadbuf = C218_LoadBuf;
+ loadlen = C218DLoad_len;
+ checksum = C218check_sum;
+ checksum_ok = C218chksum_ok;
+ break;
+ default:
+ key = C320_key;
+ keycode = C320_KeyCode;
+ loadbuf = C320_LoadBuf;
+ loadlen = C320DLoad_len;
+ checksum = C320check_sum;
+ checksum_ok = C320chksum_ok;
+ break;
+ }
+
+ usum = 0;
+ wlen = len >> 1;
+ for (i = 0; i < wlen; i++)
+ usum += le16_to_cpu(uptr[i]);
+ retry = 0;
+ do {
+ wlen = len >> 1;
+ j = 0;
+ while (wlen) {
+ len2 = (wlen > 2048) ? 2048 : wlen;
+ wlen -= len2;
+ memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
+ j += len2 << 1;
+
+ writew(len2, baseAddr + loadlen);
+ writew(0, baseAddr + key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + key) == keycode)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + key) != keycode)
+ return -EIO;
+ }
+ writew(0, baseAddr + loadlen);
+ writew(usum, baseAddr + checksum);
+ writew(0, baseAddr + key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + key) == keycode)
+ break;
+ msleep(10);
+ }
+ retry++;
+ } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
+ if (readb(baseAddr + checksum_ok) != 1)
+ return -EIO;
+
+ writew(0, baseAddr + key);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+
+ if (MOXA_IS_320(brd)) {
+ if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
+ writew(0x3800, baseAddr + TMS320_PORT1);
+ writew(0x3900, baseAddr + TMS320_PORT2);
+ writew(28499, baseAddr + TMS320_CLOCK);
+ } else {
+ writew(0x3200, baseAddr + TMS320_PORT1);
+ writew(0x3400, baseAddr + TMS320_PORT2);
+ writew(19999, baseAddr + TMS320_CLOCK);
+ }
+ }
+ writew(1, baseAddr + Disable_IRQ);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 500; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+
+ if (MOXA_IS_320(brd)) {
+ j = readw(baseAddr + Module_cnt);
+ if (j <= 0)
+ return -EIO;
+ brd->numPorts = j * 8;
+ writew(j, baseAddr + Module_no);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+ }
+ brd->intNdx = baseAddr + IRQindex;
+ brd->intPend = baseAddr + IRQpending;
+ brd->intTable = baseAddr + IRQtable;
+
+ return 0;
+}
+
+static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
+ size_t len)
+{
+ void __iomem *ofsAddr, *baseAddr = brd->basemem;
+ struct moxa_port *port;
+ int retval, i;
+
+ if (len % 2) {
+ printk(KERN_ERR "MOXA: bios length is not even\n");
+ return -EINVAL;
+ }
+
+ retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
+ if (retval)
+ return retval;
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ case MOXA_BOARD_CP204J:
+ port = brd->ports;
+ for (i = 0; i < brd->numPorts; i++, port++) {
+ port->board = brd;
+ port->DCDState = 0;
+ port->tableAddr = baseAddr + Extern_table +
+ Extern_size * i;
+ ofsAddr = port->tableAddr;
+ writew(C218rx_mask, ofsAddr + RX_mask);
+ writew(C218tx_mask, ofsAddr + TX_mask);
+ writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
+
+ writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
+
+ }
+ break;
+ default:
+ port = brd->ports;
+ for (i = 0; i < brd->numPorts; i++, port++) {
+ port->board = brd;
+ port->DCDState = 0;
+ port->tableAddr = baseAddr + Extern_table +
+ Extern_size * i;
+ ofsAddr = port->tableAddr;
+ switch (brd->numPorts) {
+ case 8:
+ writew(C320p8rx_mask, ofsAddr + RX_mask);
+ writew(C320p8tx_mask, ofsAddr + TX_mask);
+ writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
+
+ break;
+ case 16:
+ writew(C320p16rx_mask, ofsAddr + RX_mask);
+ writew(C320p16tx_mask, ofsAddr + TX_mask);
+ writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
+ break;
+
+ case 24:
+ writew(C320p24rx_mask, ofsAddr + RX_mask);
+ writew(C320p24tx_mask, ofsAddr + TX_mask);
+ writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ break;
+ case 32:
+ writew(C320p32rx_mask, ofsAddr + RX_mask);
+ writew(C320p32tx_mask, ofsAddr + TX_mask);
+ writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
+ writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
+ writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
+ writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
+{
+ void *ptr = fw->data;
+ char rsn[64];
+ u16 lens[5];
+ size_t len;
+ unsigned int a, lenp, lencnt;
+ int ret = -EINVAL;
+ struct {
+ __le32 magic; /* 0x34303430 */
+ u8 reserved1[2];
+ u8 type; /* UNIX = 3 */
+ u8 model; /* C218T=1, C320T=2, CP204=3 */
+ u8 reserved2[8];
+ __le16 len[5];
+ } *hdr = ptr;
+
+ BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
+
+ if (fw->size < MOXA_FW_HDRLEN) {
+ strcpy(rsn, "too short (even header won't fit)");
+ goto err;
+ }
+ if (hdr->magic != cpu_to_le32(0x30343034)) {
+ sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
+ goto err;
+ }
+ if (hdr->type != 3) {
+ sprintf(rsn, "not for linux, type is %u", hdr->type);
+ goto err;
+ }
+ if (moxa_check_fw_model(brd, hdr->model)) {
+ sprintf(rsn, "not for this card, model is %u", hdr->model);
+ goto err;
+ }
+
+ len = MOXA_FW_HDRLEN;
+ lencnt = hdr->model == 2 ? 5 : 3;
+ for (a = 0; a < ARRAY_SIZE(lens); a++) {
+ lens[a] = le16_to_cpu(hdr->len[a]);
+ if (lens[a] && len + lens[a] <= fw->size &&
+ moxa_check_fw(&fw->data[len]))
+ printk(KERN_WARNING "MOXA firmware: unexpected input "
+ "at offset %u, but going on\n", (u32)len);
+ if (!lens[a] && a < lencnt) {
+ sprintf(rsn, "too few entries in fw file");
+ goto err;
+ }
+ len += lens[a];
+ }
+
+ if (len != fw->size) {
+ sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
+ (u32)len);
+ goto err;
+ }
+
+ ptr += MOXA_FW_HDRLEN;
+ lenp = 0; /* bios */
+
+ strcpy(rsn, "read above");
+
+ ret = moxa_load_bios(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+
+ /* we skip the tty section (lens[1]), since we don't need it */
+ ptr += lens[lenp] + lens[lenp + 1];
+ lenp += 2; /* comm */
+
+ if (hdr->model == 2) {
+ ret = moxa_load_320b(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+ /* skip another tty */
+ ptr += lens[lenp] + lens[lenp + 1];
+ lenp += 2;
+ }
+
+ ret = moxa_load_code(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
+ return ret;
+}
+
+static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
+{
+ const struct firmware *fw;
+ const char *file;
+ struct moxa_port *p;
+ unsigned int i;
+ int ret;
+
+ brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
+ GFP_KERNEL);
+ if (brd->ports == NULL) {
+ printk(KERN_ERR "cannot allocate memory for ports\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
+ p->type = PORT_16550A;
+ p->close_delay = 5 * HZ / 10;
+ p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ init_waitqueue_head(&p->open_wait);
+ }
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ file = "c218tunx.cod";
+ break;
+ case MOXA_BOARD_CP204J:
+ file = "cp204unx.cod";
+ break;
+ default:
+ file = "c320tunx.cod";
+ break;
+ }
+
+ ret = request_firmware(&fw, file, dev);
+ if (ret) {
+ printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ file);
+ goto err_free;
+ }
+
+ ret = moxa_load_fw(brd, fw);
+
+ release_firmware(fw);
+
+ if (ret)
+ goto err_free;
+
+ spin_lock_bh(&moxa_lock);
+ brd->ready = 1;
+ if (!timer_pending(&moxaTimer))
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock_bh(&moxa_lock);
+
+ return 0;
+err_free:
+ kfree(brd->ports);
+err:
+ return ret;
+}
+
+static void moxa_board_deinit(struct moxa_board_conf *brd)
+{
+ unsigned int a, opened;
+
+ mutex_lock(&moxa_openlock);
+ spin_lock_bh(&moxa_lock);
+ brd->ready = 0;
+ spin_unlock_bh(&moxa_lock);
+
+ /* pci hot-un-plug support */
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+ tty_hangup(brd->ports[a].tty);
+ while (1) {
+ opened = 0;
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+ opened++;
+ mutex_unlock(&moxa_openlock);
+ if (!opened)
+ break;
+ msleep(50);
+ mutex_lock(&moxa_openlock);
+ }
+
+ iounmap(brd->basemem);
+ brd->basemem = NULL;
+ kfree(brd->ports);
+}
+
#ifdef CONFIG_PCI
static int __devinit moxa_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -299,10 +930,17 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
}
board = &moxa_boards[i];
- board->basemem = pci_iomap(pdev, 2, 0x4000);
+
+ retval = pci_request_region(pdev, 2, "moxa-base");
+ if (retval) {
+ dev_err(&pdev->dev, "can't request pci region 2\n");
+ goto err;
+ }
+
+ board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
- goto err;
+ goto err_reg;
}
board->boardType = board_type;
@@ -321,9 +959,21 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
}
board->busType = MOXA_BUS_TYPE_PCI;
+ retval = moxa_init_board(board, &pdev->dev);
+ if (retval)
+ goto err_base;
+
pci_set_drvdata(pdev, board);
- return (0);
+ dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
+ moxa_brdname[board_type - 1], board->numPorts);
+
+ return 0;
+err_base:
+ iounmap(board->basemem);
+ board->basemem = NULL;
+err_reg:
+ pci_release_region(pdev, 2);
err:
return retval;
}
@@ -332,8 +982,9 @@ 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;
+ moxa_board_deinit(brd);
+
+ pci_release_region(pdev, 2);
}
static struct pci_driver moxa_pci_driver = {
@@ -346,8 +997,8 @@ static struct pci_driver moxa_pci_driver = {
static int __init moxa_init(void)
{
- int i, numBoards, retval = 0;
- struct moxa_port *ch;
+ unsigned int isabrds = 0;
+ int retval = 0;
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
@@ -368,154 +1019,176 @@ static int __init moxa_init(void)
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
- for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) {
- ch->type = PORT_16550A;
- ch->port = i;
- ch->close_delay = 5 * HZ / 10;
- ch->closing_wait = 30 * HZ;
- ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- init_waitqueue_head(&ch->open_wait);
- init_completion(&ch->close_wait);
-
- setup_timer(&ch->emptyTimer, moxa_check_xmit_empty,
- (unsigned long)ch);
- }
-
- pr_debug("Moxa tty devices major number = %d\n", ttymajor);
-
if (tty_register_driver(moxaDriver)) {
- printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
+ printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
put_tty_driver(moxaDriver);
return -1;
}
- mod_timer(&moxaTimer, jiffies + HZ / 50);
-
- /* Find the boards defined in source code */
- numBoards = 0;
- for (i = 0; i < MAX_BOARDS; i++) {
- if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) ||
- (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) {
- moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType;
- if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
- moxa_boards[numBoards].numPorts = 8;
- else
- moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts;
- moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
- moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr;
- pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1,
- moxa_brdname[moxa_boards[numBoards].boardType-1],
- moxa_boards[numBoards].baseAddr);
- numBoards++;
- }
- }
- /* Find the boards defined form module args. */
+ /* Find the boards defined from module args. */
#ifdef MODULE
+ {
+ struct moxa_board_conf *brd = moxa_boards;
+ unsigned int i;
for (i = 0; i < MAX_BOARDS; i++) {
- if ((type[i] == MOXA_BOARD_C218_ISA) ||
- (type[i] == MOXA_BOARD_C320_ISA)) {
+ if (!baseaddr[i])
+ break;
+ if (type[i] == MOXA_BOARD_C218_ISA ||
+ type[i] == MOXA_BOARD_C320_ISA) {
pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1, moxa_brdname[type[i] - 1],
- (unsigned long)baseaddr[i]);
- if (numBoards >= MAX_BOARDS) {
- printk(KERN_WARNING "More than %d MOXA "
- "Intellio family boards found. Board "
- "is ignored.\n", MAX_BOARDS);
+ isabrds + 1, moxa_brdname[type[i] - 1],
+ baseaddr[i]);
+ brd->boardType = type[i];
+ brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
+ numports[i];
+ brd->busType = MOXA_BUS_TYPE_ISA;
+ brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
+ if (!brd->basemem) {
+ printk(KERN_ERR "MOXA: can't remap %lx\n",
+ baseaddr[i]);
continue;
}
- moxa_boards[numBoards].boardType = type[i];
- if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
- moxa_boards[numBoards].numPorts = 8;
- else
- moxa_boards[numBoards].numPorts = numports[i];
- moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
- moxa_boards[numBoards].baseAddr = baseaddr[i];
- numBoards++;
+ if (moxa_init_board(brd, NULL)) {
+ iounmap(brd->basemem);
+ brd->basemem = NULL;
+ continue;
+ }
+
+ printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+ "ready (%u ports, firmware loaded)\n",
+ baseaddr[i], brd->numPorts);
+
+ brd++;
+ isabrds++;
}
}
+ }
#endif
#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
if (retval) {
- printk(KERN_ERR "Can't register moxa pci driver!\n");
- if (numBoards)
+ printk(KERN_ERR "Can't register MOXA pci driver!\n");
+ if (isabrds)
retval = 0;
}
#endif
- for (i = 0; i < numBoards; i++) {
- moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr,
- 0x4000);
- }
-
return retval;
}
static void __exit moxa_exit(void)
{
- int i;
+ unsigned int i;
- del_timer_sync(&moxaTimer);
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&moxa_pci_driver);
+#endif
+
+ for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
+ if (moxa_boards[i].ready)
+ moxa_board_deinit(&moxa_boards[i]);
- for (i = 0; i < MAX_PORTS; i++)
- del_timer_sync(&moxa_ports[i].emptyTimer);
+ del_timer_sync(&moxaTimer);
if (tty_unregister_driver(moxaDriver))
printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
"serial driver\n");
put_tty_driver(moxaDriver);
-
-#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);
}
module_init(moxa_init);
module_exit(moxa_exit);
+static void moxa_close_port(struct moxa_port *ch)
+{
+ moxa_shut_down(ch);
+ MoxaPortFlushData(ch, 2);
+ ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
+ ch->tty->driver_data = NULL;
+ ch->tty = NULL;
+}
+
+static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
+ struct moxa_port *ch)
+{
+ DEFINE_WAIT(wait);
+ int retval = 0;
+ u8 dcd;
+
+ while (1) {
+ prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp)) {
+#ifdef SERIAL_DO_RESTART
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ spin_lock_bh(&moxa_lock);
+ dcd = ch->DCDState;
+ spin_unlock_bh(&moxa_lock);
+ if (dcd)
+ break;
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ finish_wait(&ch->open_wait, &wait);
+
+ return retval;
+}
+
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
+ struct moxa_board_conf *brd;
struct moxa_port *ch;
int port;
int retval;
port = tty->index;
if (port == MAX_PORTS) {
- return (0);
+ return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
}
- if (!MoxaPortIsValid(port)) {
- tty->driver_data = NULL;
- return (-ENODEV);
+ if (mutex_lock_interruptible(&moxa_openlock))
+ return -ERESTARTSYS;
+ brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
+ if (!brd->ready) {
+ mutex_unlock(&moxa_openlock);
+ return -ENODEV;
}
- ch = &moxa_ports[port];
+ ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
ch->count++;
tty->driver_data = ch;
ch->tty = tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, tty->termios);
- MoxaPortLineCtrl(ch->port, 1, 1);
- MoxaPortEnable(ch->port);
+ MoxaPortLineCtrl(ch, 1, 1);
+ MoxaPortEnable(ch);
+ MoxaSetFifo(ch, ch->type == PORT_16550A);
ch->asyncflags |= ASYNC_INITIALIZED;
}
- retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_unlock(&moxa_openlock);
- moxa_unthrottle(tty);
-
- if (ch->type == PORT_16550A) {
- MoxaSetFifo(ch->port, 1);
- } else {
- MoxaSetFifo(ch->port, 0);
- }
+ retval = 0;
+ if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
+ retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_lock(&moxa_openlock);
+ if (retval) {
+ if (ch->count) /* 0 means already hung up... */
+ if (--ch->count == 0)
+ moxa_close_port(ch);
+ } else
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+ mutex_unlock(&moxa_openlock);
- return (retval);
+ return retval;
}
static void moxa_close(struct tty_struct *tty, struct file *filp)
@@ -524,23 +1197,14 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
int port;
port = tty->index;
- if (port == MAX_PORTS) {
- return;
- }
- if (!MoxaPortIsValid(port)) {
- pr_debug("Invalid portno in moxa_close\n");
- tty->driver_data = NULL;
- return;
- }
- if (tty->driver_data == NULL) {
+ if (port == MAX_PORTS || tty_hung_up_p(filp))
return;
- }
- if (tty_hung_up_p(filp)) {
- return;
- }
- ch = (struct moxa_port *) tty->driver_data;
- if ((tty->count == 1) && (ch->count != 1)) {
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL)
+ goto unlock;
+ if (tty->count == 1 && ch->count != 1) {
printk(KERN_WARNING "moxa_close: bad serial port count; "
"tty->count is 1, ch->count is %d\n", ch->count);
ch->count = 1;
@@ -550,59 +1214,35 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
"device=%s\n", tty->name);
ch->count = 0;
}
- if (ch->count) {
- return;
- }
- ch->asyncflags |= ASYNC_CLOSING;
+ if (ch->count)
+ goto unlock;
ch->cflag = tty->termios->c_cflag;
if (ch->asyncflags & ASYNC_INITIALIZED) {
moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
- del_timer_sync(&moxa_ports[ch->port].emptyTimer);
- }
- moxa_shut_down(ch);
- MoxaPortFlushData(port, 2);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- ch->event = 0;
- ch->tty = NULL;
- if (ch->blocked_open) {
- if (ch->close_delay) {
- msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
- wake_up_interruptible(&ch->open_wait);
}
- ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- complete_all(&ch->close_wait);
+
+ moxa_close_port(ch);
+unlock:
+ mutex_unlock(&moxa_openlock);
}
static int moxa_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
- struct moxa_port *ch;
- int len, port;
- unsigned long flags;
+ struct moxa_port *ch = tty->driver_data;
+ int len;
- ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
- return (0);
- port = ch->port;
+ return 0;
- spin_lock_irqsave(&moxa_lock, flags);
- len = MoxaPortWriteData(port, (unsigned char *) buf, count);
- spin_unlock_irqrestore(&moxa_lock, flags);
+ spin_lock_bh(&moxa_lock);
+ len = MoxaPortWriteData(ch, buf, count);
+ spin_unlock_bh(&moxa_lock);
- /*********************************************
- if ( !(ch->statusflags & LOWWAIT) &&
- ((len != count) || (MoxaPortTxFree(port) <= 100)) )
- ************************************************/
ch->statusflags |= LOWWAIT;
- return (len);
+ return len;
}
static int moxa_write_room(struct tty_struct *tty)
@@ -610,27 +1250,27 @@ static int moxa_write_room(struct tty_struct *tty)
struct moxa_port *ch;
if (tty->stopped)
- return (0);
- ch = (struct moxa_port *) tty->driver_data;
+ return 0;
+ ch = tty->driver_data;
if (ch == NULL)
- return (0);
- return (MoxaPortTxFree(ch->port));
+ return 0;
+ return MoxaPortTxFree(ch);
}
static void moxa_flush_buffer(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
- MoxaPortFlushData(ch->port, 1);
+ MoxaPortFlushData(ch, 1);
tty_wakeup(tty);
}
static int moxa_chars_in_buffer(struct tty_struct *tty)
{
+ struct moxa_port *ch = tty->driver_data;
int chars;
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
/*
* Sigh...I have to check if driver_data is NULL here, because
@@ -639,8 +1279,9 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
* routine. And since the open() failed, we return 0 here. TDJ
*/
if (ch == NULL)
- return (0);
- chars = MoxaPortTxQueue(ch->port);
+ return 0;
+ lock_kernel();
+ chars = MoxaPortTxQueue(ch);
if (chars) {
/*
* Make it possible to wakeup anything waiting for output
@@ -649,73 +1290,54 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
if (!(ch->statusflags & EMPTYWAIT))
moxa_setup_empty_event(tty);
}
- return (chars);
-}
-
-static void moxa_flush_chars(struct tty_struct *tty)
-{
- /*
- * Don't think I need this, because this is called to empty the TX
- * buffer for the 16450, 16550, etc.
- */
-}
-
-static void moxa_put_char(struct tty_struct *tty, unsigned char c)
-{
- struct moxa_port *ch;
- int port;
- unsigned long flags;
-
- ch = (struct moxa_port *) tty->driver_data;
- if (ch == NULL)
- return;
- port = ch->port;
- spin_lock_irqsave(&moxa_lock, flags);
- MoxaPortWriteData(port, &c, 1);
- spin_unlock_irqrestore(&moxa_lock, flags);
- /************************************************
- if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
- *************************************************/
- ch->statusflags |= LOWWAIT;
+ unlock_kernel();
+ return chars;
}
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
- int port;
+ struct moxa_port *ch;
int flag = 0, dtr, rts;
- port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
+ return -EINVAL;
+ }
- MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr, &rts);
if (dtr)
flag |= TIOCM_DTR;
if (rts)
flag |= TIOCM_RTS;
- dtr = MoxaPortLineStatus(ch->port);
+ dtr = MoxaPortLineStatus(ch);
if (dtr & 1)
flag |= TIOCM_CTS;
if (dtr & 2)
flag |= TIOCM_DSR;
if (dtr & 4)
flag |= TIOCM_CD;
+ mutex_unlock(&moxa_openlock);
return flag;
}
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
int port;
int dtr, rts;
port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
+ return -EINVAL;
+ }
- MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr, &rts);
if (set & TIOCM_RTS)
rts = 1;
if (set & TIOCM_DTR)
@@ -724,105 +1346,51 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
rts = 0;
if (clear & TIOCM_DTR)
dtr = 0;
- MoxaPortLineCtrl(ch->port, dtr, rts);
+ MoxaPortLineCtrl(ch, dtr, rts);
+ mutex_unlock(&moxa_openlock);
return 0;
}
-static int moxa_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
- register int port;
- void __user *argp = (void __user *)arg;
- int retval;
-
- port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return (retval);
- moxa_setup_empty_event(tty);
- tty_wait_until_sent(tty, 0);
- if (!arg)
- MoxaPortSendBreak(ch->port, 0);
- return (0);
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return (retval);
- moxa_setup_empty_event(tty);
- tty_wait_until_sent(tty, 0);
- MoxaPortSendBreak(ch->port, arg);
- return (0);
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
- case TIOCSSOFTCAR:
- if(get_user(retval, (unsigned long __user *) argp))
- return -EFAULT;
- arg = retval;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- if (C_CLOCAL(tty))
- ch->asyncflags &= ~ASYNC_CHECK_CD;
- else
- ch->asyncflags |= ASYNC_CHECK_CD;
- return (0);
- case TIOCGSERIAL:
- return moxa_get_serial_info(ch, argp);
-
- case TIOCSSERIAL:
- return moxa_set_serial_info(ch, argp);
- default:
- retval = MoxaDriverIoctl(cmd, arg, port);
- }
- return (retval);
-}
-
static void moxa_throttle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags |= THROTTLE;
}
static void moxa_unthrottle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags &= ~THROTTLE;
}
static void moxa_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
+ struct ktermios *old_termios)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
moxa_set_tty_param(tty, old_termios);
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&ch->open_wait);
}
static void moxa_stop(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
- MoxaPortTxDisable(ch->port);
+ MoxaPortTxDisable(ch);
ch->statusflags |= TXSTOPPED;
}
static void moxa_start(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
@@ -830,91 +1398,143 @@ static void moxa_start(struct tty_struct *tty)
if (!(ch->statusflags & TXSTOPPED))
return;
- MoxaPortTxEnable(ch->port);
+ MoxaPortTxEnable(ch);
ch->statusflags &= ~TXSTOPPED;
}
static void moxa_hangup(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
- moxa_flush_buffer(tty);
- moxa_shut_down(ch);
- ch->event = 0;
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL) {
+ mutex_unlock(&moxa_openlock);
+ return;
+ }
ch->count = 0;
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- ch->tty = NULL;
+ moxa_close_port(ch);
+ mutex_unlock(&moxa_openlock);
+
wake_up_interruptible(&ch->open_wait);
}
-static void moxa_poll(unsigned long ignored)
+static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{
- register int card;
- struct moxa_port *ch;
- struct tty_struct *tp;
- int i, ports;
+ dcd = !!dcd;
- del_timer(&moxaTimer);
+ if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) {
+ if (!dcd)
+ tty_hangup(p->tty);
+ }
+ p->DCDState = dcd;
+}
- if (MoxaDriverPoll() < 0) {
- mod_timer(&moxaTimer, jiffies + HZ / 50);
- return;
+static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
+ u16 __iomem *ip)
+{
+ struct tty_struct *tty = p->tty;
+ void __iomem *ofsAddr;
+ unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
+ u16 intr;
+
+ if (tty) {
+ if ((p->statusflags & EMPTYWAIT) &&
+ MoxaPortTxQueue(p) == 0) {
+ p->statusflags &= ~EMPTYWAIT;
+ tty_wakeup(tty);
+ }
+ if ((p->statusflags & LOWWAIT) && !tty->stopped &&
+ MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
+ p->statusflags &= ~LOWWAIT;
+ tty_wakeup(tty);
+ }
+
+ if (inited && !(p->statusflags & THROTTLE) &&
+ MoxaPortRxQueue(p) > 0) { /* RX */
+ MoxaPortReadData(p);
+ tty_schedule_flip(tty);
+ }
+ } else {
+ p->statusflags &= ~EMPTYWAIT;
+ MoxaPortFlushData(p, 0); /* flush RX */
}
+
+ if (!handle) /* nothing else to do */
+ return 0;
+
+ intr = readw(ip); /* port irq status */
+ if (intr == 0)
+ return 0;
+
+ writew(0, ip); /* ACK port */
+ ofsAddr = p->tableAddr;
+ if (intr & IntrTx) /* disable tx intr */
+ writew(readw(ofsAddr + HostStat) & ~WakeupTx,
+ ofsAddr + HostStat);
+
+ if (!inited)
+ return 0;
+
+ if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ tty_schedule_flip(tty);
+ }
+
+ if (intr & IntrLine)
+ moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
+
+ return 0;
+}
+
+static void moxa_poll(unsigned long ignored)
+{
+ struct moxa_board_conf *brd;
+ u16 __iomem *ip;
+ unsigned int card, port, served = 0;
+
+ spin_lock(&moxa_lock);
for (card = 0; card < MAX_BOARDS; card++) {
- if ((ports = MoxaPortsOfCard(card)) <= 0)
+ brd = &moxa_boards[card];
+ if (!brd->ready)
continue;
- ch = &moxa_ports[card * MAX_PORTS_PER_BOARD];
- for (i = 0; i < ports; i++, ch++) {
- if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
- continue;
- if (!(ch->statusflags & THROTTLE) &&
- (MoxaPortRxQueue(ch->port) > 0))
- moxa_receive_data(ch);
- if ((tp = ch->tty) == 0)
- continue;
- if (ch->statusflags & LOWWAIT) {
- if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
- if (!tp->stopped) {
- ch->statusflags &= ~LOWWAIT;
- tty_wakeup(tp);
- }
- }
- }
- if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {
- tty_insert_flip_char(tp, 0, TTY_BREAK);
- tty_schedule_flip(tp);
- }
- if (MoxaPortDCDChange(ch->port)) {
- if (ch->asyncflags & ASYNC_CHECK_CD) {
- if (MoxaPortDCDON(ch->port))
- wake_up_interruptible(&ch->open_wait);
- else {
- tty_hangup(tp);
- wake_up_interruptible(&ch->open_wait);
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- }
+
+ served++;
+
+ ip = NULL;
+ if (readb(brd->intPend) == 0xff)
+ ip = brd->intTable + readb(brd->intNdx);
+
+ for (port = 0; port < brd->numPorts; port++)
+ moxa_poll_port(&brd->ports[port], !!ip, ip + port);
+
+ if (ip)
+ writeb(0, brd->intPend); /* ACK */
+
+ if (moxaLowWaterChk) {
+ struct moxa_port *p = brd->ports;
+ for (port = 0; port < brd->numPorts; port++, p++)
+ if (p->lowChkFlag) {
+ p->lowChkFlag = 0;
+ moxa_low_water_check(p->tableAddr);
}
- }
}
}
+ moxaLowWaterChk = 0;
- mod_timer(&moxaTimer, jiffies + HZ / 50);
+ if (served)
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock(&moxa_lock);
}
/******************************************************************************/
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
- register struct ktermios *ts;
- struct moxa_port *ch;
+ register struct ktermios *ts = tty->termios;
+ struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;
- ch = (struct moxa_port *) tty->driver_data;
- ts = tty->termios;
- if (ts->c_cflag & CLOCAL)
- ch->asyncflags &= ~ASYNC_CHECK_CD;
- else
- ch->asyncflags |= ASYNC_CHECK_CD;
rts = cts = txflow = rxflow = xany = 0;
if (ts->c_cflag & CRTSCTS)
rts = cts = 1;
@@ -927,776 +1547,60 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term
/* Clear the features we don't support */
ts->c_cflag &= ~CMSPAR;
- MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
- baud = MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
+ MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
+ baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
if (baud == -1)
baud = tty_termios_baud_rate(old_termios);
/* Not put the baud rate into the termios data */
tty_encode_baud_rate(tty, baud, baud);
}
-static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
- struct moxa_port *ch)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int retval;
- int do_clocal = C_CLOCAL(tty);
-
- /*
- * 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) || (ch->asyncflags & ASYNC_CLOSING)) {
- if (ch->asyncflags & ASYNC_CLOSING)
- wait_for_completion_interruptible(&ch->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- return (-EAGAIN);
- else
- return (-ERESTARTSYS);
-#else
- return (-EAGAIN);
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return (0);
- }
- /*
- * Block waiting for the carrier detect and the line to become free
- */
- retval = 0;
- add_wait_queue(&ch->open_wait, &wait);
- pr_debug("block_til_ready before block: ttys%d, count = %d\n",
- ch->port, ch->count);
- spin_lock_irqsave(&moxa_lock, flags);
- if (!tty_hung_up_p(filp))
- ch->count--;
- ch->blocked_open++;
- spin_unlock_irqrestore(&moxa_lock, flags);
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
- MoxaPortDCDON(ch->port)))
- break;
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ch->open_wait, &wait);
-
- spin_lock_irqsave(&moxa_lock, flags);
- if (!tty_hung_up_p(filp))
- ch->count++;
- ch->blocked_open--;
- spin_unlock_irqrestore(&moxa_lock, flags);
- pr_debug("block_til_ready after blocking: ttys%d, count = %d\n",
- ch->port, ch->count);
- if (retval)
- return (retval);
- /* FIXME: review to see if we need to use set_bit on these */
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
static void moxa_setup_empty_event(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&moxa_lock, flags);
+ spin_lock_bh(&moxa_lock);
ch->statusflags |= EMPTYWAIT;
- mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
- spin_unlock_irqrestore(&moxa_lock, flags);
-}
-
-static void moxa_check_xmit_empty(unsigned long data)
-{
- struct moxa_port *ch;
-
- ch = (struct moxa_port *) data;
- if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
- if (MoxaPortTxQueue(ch->port) == 0) {
- ch->statusflags &= ~EMPTYWAIT;
- tty_wakeup(ch->tty);
- return;
- }
- mod_timer(&moxa_ports[ch->port].emptyTimer,
- round_jiffies(jiffies + HZ));
- } else
- ch->statusflags &= ~EMPTYWAIT;
+ spin_unlock_bh(&moxa_lock);
}
static void moxa_shut_down(struct moxa_port *ch)
{
- struct tty_struct *tp;
+ struct tty_struct *tp = ch->tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
- tp = ch->tty;
-
- MoxaPortDisable(ch->port);
+ MoxaPortDisable(ch);
/*
* If we're a modem control device and HUPCL is on, drop RTS & DTR.
*/
- if (tp->termios->c_cflag & HUPCL)
- MoxaPortLineCtrl(ch->port, 0, 0);
+ if (C_HUPCL(tp))
+ MoxaPortLineCtrl(ch, 0, 0);
+ spin_lock_bh(&moxa_lock);
ch->asyncflags &= ~ASYNC_INITIALIZED;
+ spin_unlock_bh(&moxa_lock);
}
-static void moxa_receive_data(struct moxa_port *ch)
-{
- struct tty_struct *tp;
- struct ktermios *ts;
- unsigned long flags;
-
- ts = NULL;
- tp = ch->tty;
- if (tp)
- ts = tp->termios;
- /**************************************************
- if ( !tp || !ts || !(ts->c_cflag & CREAD) ) {
- *****************************************************/
- if (!tp || !ts) {
- MoxaPortFlushData(ch->port, 0);
- return;
- }
- spin_lock_irqsave(&moxa_lock, flags);
- MoxaPortReadData(ch->port, tp);
- spin_unlock_irqrestore(&moxa_lock, flags);
- tty_schedule_flip(tp);
-}
-
-#define Magic_code 0x404
-
-/*
- * System Configuration
- */
-/*
- * for C218 BIOS initialization
- */
-#define C218_ConfBase 0x800
-#define C218_status (C218_ConfBase + 0) /* BIOS running status */
-#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
-#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
-#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
-#define C218check_sum (C218_ConfBase + 8) /* BYTE */
-#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
-#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
-#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
-#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
-#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
-
-#define C218_LoadBuf 0x0F00
-#define C218_KeyCode 0x218
-#define CP204J_KeyCode 0x204
-
-/*
- * for C320 BIOS initialization
- */
-#define C320_ConfBase 0x800
-#define C320_LoadBuf 0x0f00
-#define STS_init 0x05 /* for C320_status */
-
-#define C320_status C320_ConfBase + 0 /* BIOS running status */
-#define C320_diag C320_ConfBase + 2 /* diagnostic status */
-#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
-#define C320DLoad_len C320_ConfBase + 6 /* WORD */
-#define C320check_sum C320_ConfBase + 8 /* WORD */
-#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
-#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
-#define C320UART_no C320_ConfBase + 0x0e /* WORD */
-
-#define C320_KeyCode 0x320
-
-#define FixPage_addr 0x0000 /* starting addr of static page */
-#define DynPage_addr 0x2000 /* starting addr of dynamic page */
-#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
-#define Control_reg 0x1ff0 /* select page and reset control */
-#define HW_reset 0x80
-
-/*
- * Function Codes
- */
-#define FC_CardReset 0x80
-#define FC_ChannelReset 1 /* C320 firmware not supported */
-#define FC_EnableCH 2
-#define FC_DisableCH 3
-#define FC_SetParam 4
-#define FC_SetMode 5
-#define FC_SetRate 6
-#define FC_LineControl 7
-#define FC_LineStatus 8
-#define FC_XmitControl 9
-#define FC_FlushQueue 10
-#define FC_SendBreak 11
-#define FC_StopBreak 12
-#define FC_LoopbackON 13
-#define FC_LoopbackOFF 14
-#define FC_ClrIrqTable 15
-#define FC_SendXon 16
-#define FC_SetTermIrq 17 /* C320 firmware not supported */
-#define FC_SetCntIrq 18 /* C320 firmware not supported */
-#define FC_SetBreakIrq 19
-#define FC_SetLineIrq 20
-#define FC_SetFlowCtl 21
-#define FC_GenIrq 22
-#define FC_InCD180 23
-#define FC_OutCD180 24
-#define FC_InUARTreg 23
-#define FC_OutUARTreg 24
-#define FC_SetXonXoff 25
-#define FC_OutCD180CCR 26
-#define FC_ExtIQueue 27
-#define FC_ExtOQueue 28
-#define FC_ClrLineIrq 29
-#define FC_HWFlowCtl 30
-#define FC_GetClockRate 35
-#define FC_SetBaud 36
-#define FC_SetDataMode 41
-#define FC_GetCCSR 43
-#define FC_GetDataError 45
-#define FC_RxControl 50
-#define FC_ImmSend 51
-#define FC_SetXonState 52
-#define FC_SetXoffState 53
-#define FC_SetRxFIFOTrig 54
-#define FC_SetTxFIFOCnt 55
-#define FC_UnixRate 56
-#define FC_UnixResetTimer 57
-
-#define RxFIFOTrig1 0
-#define RxFIFOTrig4 1
-#define RxFIFOTrig8 2
-#define RxFIFOTrig14 3
-
-/*
- * Dual-Ported RAM
- */
-#define DRAM_global 0
-#define INT_data (DRAM_global + 0)
-#define Config_base (DRAM_global + 0x108)
-
-#define IRQindex (INT_data + 0)
-#define IRQpending (INT_data + 4)
-#define IRQtable (INT_data + 8)
-
-/*
- * Interrupt Status
- */
-#define IntrRx 0x01 /* receiver data O.K. */
-#define IntrTx 0x02 /* transmit buffer empty */
-#define IntrFunc 0x04 /* function complete */
-#define IntrBreak 0x08 /* received break */
-#define IntrLine 0x10 /* line status change
- for transmitter */
-#define IntrIntr 0x20 /* received INTR code */
-#define IntrQuit 0x40 /* received QUIT code */
-#define IntrEOF 0x80 /* received EOF code */
-
-#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
-#define IntrTxTrigger 0x200 /* tx data count below trigger value */
-
-#define Magic_no (Config_base + 0)
-#define Card_model_no (Config_base + 2)
-#define Total_ports (Config_base + 4)
-#define Module_cnt (Config_base + 8)
-#define Module_no (Config_base + 10)
-#define Timer_10ms (Config_base + 14)
-#define Disable_IRQ (Config_base + 20)
-#define TMS320_PORT1 (Config_base + 22)
-#define TMS320_PORT2 (Config_base + 24)
-#define TMS320_CLOCK (Config_base + 26)
-
-/*
- * DATA BUFFER in DRAM
- */
-#define Extern_table 0x400 /* Base address of the external table
- (24 words * 64) total 3K bytes
- (24 words * 128) total 6K bytes */
-#define Extern_size 0x60 /* 96 bytes */
-#define RXrptr 0x00 /* read pointer for RX buffer */
-#define RXwptr 0x02 /* write pointer for RX buffer */
-#define TXrptr 0x04 /* read pointer for TX buffer */
-#define TXwptr 0x06 /* write pointer for TX buffer */
-#define HostStat 0x08 /* IRQ flag and general flag */
-#define FlagStat 0x0A
-#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
- /* x x x x | | | | */
- /* | | | + CTS flow */
- /* | | +--- RTS flow */
- /* | +------ TX Xon/Xoff */
- /* +--------- RX Xon/Xoff */
-#define Break_cnt 0x0E /* received break count */
-#define CD180TXirq 0x10 /* if non-0: enable TX irq */
-#define RX_mask 0x12
-#define TX_mask 0x14
-#define Ofs_rxb 0x16
-#define Ofs_txb 0x18
-#define Page_rxb 0x1A
-#define Page_txb 0x1C
-#define EndPage_rxb 0x1E
-#define EndPage_txb 0x20
-#define Data_error 0x22
-#define RxTrigger 0x28
-#define TxTrigger 0x2a
-
-#define rRXwptr 0x34
-#define Low_water 0x36
-
-#define FuncCode 0x40
-#define FuncArg 0x42
-#define FuncArg1 0x44
-
-#define C218rx_size 0x2000 /* 8K bytes */
-#define C218tx_size 0x8000 /* 32K bytes */
-
-#define C218rx_mask (C218rx_size - 1)
-#define C218tx_mask (C218tx_size - 1)
-
-#define C320p8rx_size 0x2000
-#define C320p8tx_size 0x8000
-#define C320p8rx_mask (C320p8rx_size - 1)
-#define C320p8tx_mask (C320p8tx_size - 1)
-
-#define C320p16rx_size 0x2000
-#define C320p16tx_size 0x4000
-#define C320p16rx_mask (C320p16rx_size - 1)
-#define C320p16tx_mask (C320p16tx_size - 1)
-
-#define C320p24rx_size 0x2000
-#define C320p24tx_size 0x2000
-#define C320p24rx_mask (C320p24rx_size - 1)
-#define C320p24tx_mask (C320p24tx_size - 1)
-
-#define C320p32rx_size 0x1000
-#define C320p32tx_size 0x1000
-#define C320p32rx_mask (C320p32rx_size - 1)
-#define C320p32tx_mask (C320p32tx_size - 1)
-
-#define Page_size 0x2000
-#define Page_mask (Page_size - 1)
-#define C218rx_spage 3
-#define C218tx_spage 4
-#define C218rx_pageno 1
-#define C218tx_pageno 4
-#define C218buf_pageno 5
-
-#define C320p8rx_spage 3
-#define C320p8tx_spage 4
-#define C320p8rx_pgno 1
-#define C320p8tx_pgno 4
-#define C320p8buf_pgno 5
-
-#define C320p16rx_spage 3
-#define C320p16tx_spage 4
-#define C320p16rx_pgno 1
-#define C320p16tx_pgno 2
-#define C320p16buf_pgno 3
-
-#define C320p24rx_spage 3
-#define C320p24tx_spage 4
-#define C320p24rx_pgno 1
-#define C320p24tx_pgno 1
-#define C320p24buf_pgno 2
-
-#define C320p32rx_spage 3
-#define C320p32tx_ofs C320p32rx_size
-#define C320p32tx_spage 3
-#define C320p32buf_pgno 1
-
-/*
- * Host Status
- */
-#define WakeupRx 0x01
-#define WakeupTx 0x02
-#define WakeupBreak 0x08
-#define WakeupLine 0x10
-#define WakeupIntr 0x20
-#define WakeupQuit 0x40
-#define WakeupEOF 0x80 /* used in VTIME control */
-#define WakeupRxTrigger 0x100
-#define WakeupTxTrigger 0x200
-/*
- * Flag status
- */
-#define Rx_over 0x01
-#define Xoff_state 0x02
-#define Tx_flowOff 0x04
-#define Tx_enable 0x08
-#define CTS_state 0x10
-#define DSR_state 0x20
-#define DCD_state 0x80
-/*
- * FlowControl
- */
-#define CTS_FlowCtl 1
-#define RTS_FlowCtl 2
-#define Tx_FlowCtl 4
-#define Rx_FlowCtl 8
-#define IXM_IXANY 0x10
-
-#define LowWater 128
-
-#define DTR_ON 1
-#define RTS_ON 2
-#define CTS_ON 1
-#define DSR_ON 2
-#define DCD_ON 8
-
-/* mode definition */
-#define MX_CS8 0x03
-#define MX_CS7 0x02
-#define MX_CS6 0x01
-#define MX_CS5 0x00
-
-#define MX_STOP1 0x00
-#define MX_STOP15 0x04
-#define MX_STOP2 0x08
-
-#define MX_PARNONE 0x00
-#define MX_PAREVEN 0x40
-#define MX_PARODD 0xC0
-
-/*
- * Query
- */
-
-struct mon_str {
- int tick;
- int rxcnt[MAX_PORTS];
- int txcnt[MAX_PORTS];
-};
-
-#define DCD_changed 0x01
-#define DCD_oldstate 0x80
-
-static unsigned char moxaBuff[10240];
-static int moxaLowWaterChk;
-static int moxaCard;
-static struct mon_str moxaLog;
-static int moxaFuncTout = HZ / 2;
-
-static void moxafunc(void __iomem *, int, ushort);
-static void moxa_wait_finish(void __iomem *);
-static void moxa_low_water_check(void __iomem *);
-static int moxaloadbios(int, unsigned char __user *, int);
-static int moxafindcard(int);
-static int moxaload320b(int, unsigned char __user *, int);
-static int moxaloadcode(int, unsigned char __user *, int);
-static int moxaloadc218(int, void __iomem *, int);
-static int moxaloadc320(int, void __iomem *, int, int *);
-
/*****************************************************************************
* Driver level functions: *
- * 1. MoxaDriverInit(void); *
- * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); *
- * 3. MoxaDriverPoll(void); *
*****************************************************************************/
-void MoxaDriverInit(void)
-{
- 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++) {
- p = &moxa_ports[i];
- p->chkPort = 0;
- p->lowChkFlag = 0;
- p->lineCtrl = 0;
- moxaLog.rxcnt[i] = 0;
- moxaLog.txcnt[i] = 0;
- }
-}
-
-#define MOXA 0x400
-#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
-#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
-#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */
-#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */
-#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */
-#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */
-#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */
-#define MOXA_GETDATACOUNT (MOXA + 23)
-#define MOXA_GET_IOQUEUE (MOXA + 27)
-#define MOXA_FLUSH_QUEUE (MOXA + 28)
-#define MOXA_GET_CONF (MOXA + 35) /* configuration */
-#define MOXA_GET_MAJOR (MOXA + 63)
-#define MOXA_GET_CUMAJOR (MOXA + 64)
-#define MOXA_GETMSTATUS (MOXA + 65)
-
-struct dl_str {
- char __user *buf;
- int len;
- int cardno;
-};
-
-static struct dl_str dltmp;
-
-void MoxaPortFlushData(int port, int mode)
+static void MoxaPortFlushData(struct moxa_port *port, int mode)
{
void __iomem *ofsAddr;
- if ((mode < 0) || (mode > 2))
+ if (mode < 0 || mode > 2)
return;
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_FlushQueue, mode);
if (mode != 1) {
- moxa_ports[port].lowChkFlag = 0;
+ port->lowChkFlag = 0;
moxa_low_water_check(ofsAddr);
}
}
-int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
-{
- int i;
- int status;
- int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
- void __user *argp = (void __user *)arg;
-
- 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) &&
- (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) &&
- (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS))
- return (-EINVAL);
- }
- switch (cmd) {
- case MOXA_GET_CONF:
- if(copy_to_user(argp, &moxa_boards, MAX_BOARDS *
- sizeof(struct moxa_board_conf)))
- return -EFAULT;
- return (0);
- case MOXA_INIT_DRIVER:
- if ((int) arg == 0x404)
- MoxaDriverInit();
- return (0);
- case MOXA_GETDATACOUNT:
- moxaLog.tick = jiffies;
- 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: {
- 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;
- }
- return (0);
- } case MOXA_GET_OQUEUE:
- i = MoxaPortTxQueue(port);
- return put_user(i, (unsigned long __user *)argp);
- case MOXA_GET_IQUEUE:
- i = MoxaPortRxQueue(port);
- return put_user(i, (unsigned long __user *)argp);
- case MOXA_GET_MAJOR:
- if(copy_to_user(argp, &ttymajor, sizeof(int)))
- return -EFAULT;
- return 0;
- case MOXA_GET_CUMAJOR:
- i = 0;
- if(copy_to_user(argp, &i, sizeof(int)))
- return -EFAULT;
- return 0;
- 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(p->port);
- if (status & 1)
- tmp.cts = 1;
- if (status & 2)
- tmp.dsr = 1;
- if (status & 4)
- tmp.dcd = 1;
- }
-
- if (!p->tty || !p->tty->termios)
- tmp.cflag = p->cflag;
- else
- tmp.cflag = p->tty->termios->c_cflag;
-copy:
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- return 0;
- } default:
- return (-ENOIOCTLCMD);
- case MOXA_LOAD_BIOS:
- case MOXA_FIND_BOARD:
- case MOXA_LOAD_C320B:
- case MOXA_LOAD_CODE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- break;
- }
-
- if(copy_from_user(&dltmp, argp, sizeof(struct dl_str)))
- return -EFAULT;
- if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0)
- return -EINVAL;
-
- switch(cmd)
- {
- case MOXA_LOAD_BIOS:
- i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
- return (i);
- case MOXA_FIND_BOARD:
- return moxafindcard(dltmp.cardno);
- case MOXA_LOAD_C320B:
- moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
- default: /* to keep gcc happy */
- return (0);
- case MOXA_LOAD_CODE:
- i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
- if (i == -1)
- return (-EFAULT);
- return (i);
-
- }
-}
-
-int MoxaDriverPoll(void)
-{
- struct moxa_board_conf *brd;
- register ushort temp;
- register int card;
- void __iomem *ofsAddr;
- void __iomem *ip;
- int port, p, ports;
-
- if (moxaCard == 0)
- return (-1);
- for (card = 0; card < MAX_BOARDS; card++) {
- brd = &moxa_boards[card];
- if (brd->loadstat == 0)
- continue;
- if ((ports = brd->numPorts) == 0)
- continue;
- 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 = moxa_ports[p].tableAddr;
- if (temp & IntrTx)
- writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
- if (temp & IntrBreak) {
- moxa_ports[p].breakCnt++;
- }
- if (temp & IntrLine) {
- if (readb(ofsAddr + FlagStat) & DCD_state) {
- if ((moxa_ports[p].DCDState & DCD_oldstate) == 0)
- moxa_ports[p].DCDState = (DCD_oldstate |
- DCD_changed);
- } else {
- if (moxa_ports[p].DCDState & DCD_oldstate)
- moxa_ports[p].DCDState = DCD_changed;
- }
- }
- }
- }
- writeb(0, brd->intPend);
- }
- if (moxaLowWaterChk) {
- p = card * MAX_PORTS_PER_BOARD;
- for (port = 0; port < ports; port++, p++) {
- if (moxa_ports[p].lowChkFlag) {
- moxa_ports[p].lowChkFlag = 0;
- ofsAddr = moxa_ports[p].tableAddr;
- moxa_low_water_check(ofsAddr);
- }
- }
- }
- }
- moxaLowWaterChk = 0;
- return (0);
-}
-
-/*****************************************************************************
- * Card level function: *
- * 1. MoxaPortsOfCard(int cardno); *
- *****************************************************************************/
-int MoxaPortsOfCard(int cardno)
-{
-
- if (moxa_boards[cardno].boardType == 0)
- return (0);
- return (moxa_boards[cardno].numPorts);
-}
-
-/*****************************************************************************
- * Port level functions: *
- * 1. MoxaPortIsValid(int port); *
- * 2. MoxaPortEnable(int port); *
- * 3. MoxaPortDisable(int port); *
- * 4. MoxaPortGetMaxBaud(int port); *
- * 6. MoxaPortSetBaud(int port, long baud); *
- * 8. MoxaPortSetTermio(int port, unsigned char *termio); *
- * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); *
- * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); *
- * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); *
- * 12. MoxaPortLineStatus(int port); *
- * 13. MoxaPortDCDChange(int port); *
- * 14. MoxaPortDCDON(int port); *
- * 15. MoxaPortFlushData(int port, int mode); *
- * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
- * 17. MoxaPortReadData(int port, struct tty_struct *tty); *
- * 20. MoxaPortTxQueue(int port); *
- * 21. MoxaPortTxFree(int port); *
- * 22. MoxaPortRxQueue(int port); *
- * 24. MoxaPortTxDisable(int port); *
- * 25. MoxaPortTxEnable(int port); *
- * 27. MoxaPortResetBrkCnt(int port); *
- * 30. MoxaPortSendBreak(int port, int ticks); *
- *****************************************************************************/
/*
* Moxa Port Number Description:
*
@@ -1733,33 +1637,6 @@ int MoxaPortsOfCard(int cardno)
* -ENOIOCTLCMD
*
*
- * Function 3: Moxa driver polling process routine.
- * Syntax:
- * int MoxaDriverPoll(void);
- *
- * return: 0 ; polling O.K.
- * -1 : no any Moxa card.
- *
- *
- * Function 4: Get the ports of this card.
- * Syntax:
- * int MoxaPortsOfCard(int cardno);
- *
- * int cardno : card number (0 - 3)
- *
- * return: 0 : this card is invalid
- * 8/16/24/32
- *
- *
- * Function 5: Check this port is valid or invalid
- * Syntax:
- * int MoxaPortIsValid(int port);
- * int port : port number (0 - 127, ref port description)
- *
- * return: 0 : this port is invalid
- * 1 : this port is valid
- *
- *
* Function 6: Enable this port to start Tx/Rx data.
* Syntax:
* void MoxaPortEnable(int port);
@@ -1772,18 +1649,9 @@ int MoxaPortsOfCard(int cardno)
* int port : port number (0 - 127)
*
*
- * Function 8: Get the maximun available baud rate of this port.
- * Syntax:
- * long MoxaPortGetMaxBaud(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : this port is invalid
- * 38400/57600/115200 bps
- *
- *
* Function 10: Setting baud rate of this port.
* Syntax:
- * long MoxaPortSetBaud(int port, long baud);
+ * speed_t MoxaPortSetBaud(int port, speed_t baud);
* int port : port number (0 - 127)
* long baud : baud rate (50 - 115200)
*
@@ -1850,25 +1718,6 @@ int MoxaPortsOfCard(int cardno)
* Bit 2 - DCD state (0: off, 1: on)
*
*
- * Function 17: Check the DCD state has changed since the last read
- * of this function.
- * Syntax:
- * int MoxaPortDCDChange(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : no changed
- * 1 : DCD has changed
- *
- *
- * Function 18: Check ths current DCD state is ON or not.
- * Syntax:
- * int MoxaPortDCDON(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : DCD off
- * 1 : DCD on
- *
- *
* Function 19: Flush the Rx/Tx buffer data of this port.
* Syntax:
* void MoxaPortFlushData(int port, int mode);
@@ -1942,40 +1791,20 @@ int MoxaPortsOfCard(int cardno)
* return: 0 - .. : BREAK signal count
*
*
- * Function 34: Send out a BREAK signal.
- * Syntax:
- * void MoxaPortSendBreak(int port, int ms100);
- * int port : port number (0 - 127)
- * int ms100 : break signal time interval.
- * unit: 100 mini-second. if ms100 == 0, it will
- * send out a about 250 ms BREAK signal.
- *
*/
-int MoxaPortIsValid(int port)
-{
-
- if (moxaCard == 0)
- return (0);
- if (moxa_ports[port].chkPort == 0)
- return (0);
- return (1);
-}
-void MoxaPortEnable(int port)
+static void MoxaPortEnable(struct moxa_port *port)
{
void __iomem *ofsAddr;
- int MoxaPortLineStatus(int);
- short lowwater = 512;
+ u16 lowwater = 512;
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
writew(lowwater, ofsAddr + Low_water);
- 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)) {
+ if (MOXA_IS_320(port->board))
moxafunc(ofsAddr, FC_SetBreakIrq, 0);
- } else {
- writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
- }
+ else
+ writew(readw(ofsAddr + HostStat) | WakeupBreak,
+ ofsAddr + HostStat);
moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
moxafunc(ofsAddr, FC_FlushQueue, 2);
@@ -1984,9 +1813,9 @@ void MoxaPortEnable(int port)
MoxaPortLineStatus(port);
}
-void MoxaPortDisable(int port)
+static void MoxaPortDisable(struct moxa_port *port)
{
- void __iomem *ofsAddr = moxa_ports[port].tableAddr;
+ void __iomem *ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */
moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
@@ -1994,49 +1823,32 @@ void MoxaPortDisable(int port)
moxafunc(ofsAddr, FC_DisableCH, Magic_code);
}
-long MoxaPortGetMaxBaud(int 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))
- return (460800L);
- else
- return (921600L);
-}
-
-
-long MoxaPortSetBaud(int port, long baud)
+static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
{
- void __iomem *ofsAddr;
- long max, clock;
- unsigned int val;
+ void __iomem *ofsAddr = port->tableAddr;
+ unsigned int clock, val;
+ speed_t max;
- if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
- return (0);
- ofsAddr = moxa_ports[port].tableAddr;
+ max = MOXA_IS_320(port->board) ? 460800 : 921600;
+ if (baud < 50)
+ return 0;
if (baud > max)
baud = max;
- if (max == 38400L)
- clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */
- else if (max == 57600L)
- clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */
- else
- clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */
+ clock = 921600;
val = clock / baud;
moxafunc(ofsAddr, FC_SetBaud, val);
baud = clock / val;
- moxa_ports[port].curBaud = baud;
- return (baud);
+ return baud;
}
-int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
+static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
+ speed_t baud)
{
void __iomem *ofsAddr;
tcflag_t cflag;
tcflag_t mode = 0;
- if (moxa_ports[port].chkPort == 0 || termio == 0)
- return (-1);
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
cflag = termio->c_cflag; /* termio->c_cflag */
mode = termio->c_cflag & CSIZE;
@@ -2065,13 +1877,11 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
} else
mode |= MX_PARNONE;
- moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+ moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
+
+ if (MOXA_IS_320(port->board) && baud >= 921600)
+ return -1;
- 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)) {
- if (baud >= 921600L)
- return (-1);
- }
baud = MoxaPortSetBaud(port, baud);
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
@@ -2081,51 +1891,37 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
moxa_wait_finish(ofsAddr);
}
- return (baud);
+ return baud;
}
-int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
+static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
+ int *rtsState)
{
+ if (dtrState)
+ *dtrState = !!(port->lineCtrl & DTR_ON);
+ if (rtsState)
+ *rtsState = !!(port->lineCtrl & RTS_ON);
- if (!MoxaPortIsValid(port))
- return (-1);
- if (dtrState) {
- if (moxa_ports[port].lineCtrl & DTR_ON)
- *dtrState = 1;
- else
- *dtrState = 0;
- }
- if (rtsState) {
- if (moxa_ports[port].lineCtrl & RTS_ON)
- *rtsState = 1;
- else
- *rtsState = 0;
- }
- return (0);
+ return 0;
}
-void MoxaPortLineCtrl(int port, int dtr, int rts)
+static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
{
- void __iomem *ofsAddr;
- int mode;
+ u8 mode = 0;
- ofsAddr = moxa_ports[port].tableAddr;
- mode = 0;
if (dtr)
mode |= DTR_ON;
if (rts)
mode |= RTS_ON;
- moxa_ports[port].lineCtrl = mode;
- moxafunc(ofsAddr, FC_LineControl, mode);
+ port->lineCtrl = mode;
+ moxafunc(port->tableAddr, FC_LineControl, mode);
}
-void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany)
+static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
+ int txflow, int rxflow, int txany)
{
- void __iomem *ofsAddr;
- int mode;
+ int mode = 0;
- ofsAddr = moxa_ports[port].tableAddr;
- mode = 0;
if (rts)
mode |= RTS_FlowCtl;
if (cts)
@@ -2136,81 +1932,50 @@ void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int tx
mode |= Rx_FlowCtl;
if (txany)
mode |= IXM_IXANY;
- moxafunc(ofsAddr, FC_SetFlowCtl, mode);
+ moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
}
-int MoxaPortLineStatus(int port)
+static int MoxaPortLineStatus(struct moxa_port *port)
{
void __iomem *ofsAddr;
int val;
- 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)) {
+ ofsAddr = port->tableAddr;
+ if (MOXA_IS_320(port->board)) {
moxafunc(ofsAddr, FC_LineStatus, 0);
val = readw(ofsAddr + FuncArg);
} else {
val = readw(ofsAddr + FlagStat) >> 4;
}
val &= 0x0B;
- if (val & 8) {
+ if (val & 8)
val |= 4;
- if ((moxa_ports[port].DCDState & DCD_oldstate) == 0)
- moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed);
- } else {
- if (moxa_ports[port].DCDState & DCD_oldstate)
- moxa_ports[port].DCDState = DCD_changed;
- }
+ spin_lock_bh(&moxa_lock);
+ moxa_new_dcdstate(port, val & 8);
+ spin_unlock_bh(&moxa_lock);
val &= 7;
- return (val);
-}
-
-int MoxaPortDCDChange(int port)
-{
- int n;
-
- if (moxa_ports[port].chkPort == 0)
- return (0);
- n = moxa_ports[port].DCDState;
- moxa_ports[port].DCDState &= ~DCD_changed;
- n &= DCD_changed;
- return (n);
-}
-
-int MoxaPortDCDON(int port)
-{
- int n;
-
- if (moxa_ports[port].chkPort == 0)
- return (0);
- if (moxa_ports[port].DCDState & DCD_oldstate)
- n = 1;
- else
- n = 0;
- return (n);
+ return val;
}
-int MoxaPortWriteData(int port, unsigned char * buffer, int len)
+static int MoxaPortWriteData(struct moxa_port *port,
+ const unsigned char *buffer, int len)
{
- int c, total, i;
- ushort tail;
- int cnt;
- ushort head, tx_mask, spage, epage;
- ushort pageno, pageofs, bufhead;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ unsigned int c, total;
+ u16 head, tail, tx_mask, spage, epage;
+ u16 pageno, pageofs, bufhead;
- ofsAddr = moxa_ports[port].tableAddr;
- baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
+ ofsAddr = port->tableAddr;
+ baseAddr = port->board->basemem;
tx_mask = readw(ofsAddr + TX_mask);
spage = readw(ofsAddr + Page_txb);
epage = readw(ofsAddr + EndPage_txb);
tail = readw(ofsAddr + TXwptr);
head = readw(ofsAddr + TXrptr);
- c = (head > tail) ? (head - tail - 1)
- : (head - tail + tx_mask);
+ c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
if (c > len)
c = len;
- moxaLog.txcnt[port] += c;
+ moxaLog.txcnt[port->tty->index] += c;
total = c;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_txb);
@@ -2222,249 +1987,179 @@ int MoxaPortWriteData(int port, unsigned char * buffer, int len)
len = tx_mask + 1 - tail;
len = (c > len) ? len : c;
ofs = baseAddr + DynPage_addr + bufhead + tail;
- for (i = 0; i < len; i++)
- writeb(*buffer++, ofs + i);
+ memcpy_toio(ofs, buffer, len);
+ buffer += len;
tail = (tail + len) & tx_mask;
c -= len;
}
- writew(tail, ofsAddr + TXwptr);
} else {
- len = c;
pageno = spage + (tail >> 13);
pageofs = tail & Page_mask;
- do {
- cnt = Page_size - pageofs;
- if (cnt > c)
- cnt = c;
- c -= cnt;
+ while (c > 0) {
+ len = Page_size - pageofs;
+ if (len > c)
+ len = c;
writeb(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
- for (i = 0; i < cnt; i++)
- writeb(*buffer++, ofs + i);
- if (c == 0) {
- writew((tail + len) & tx_mask, ofsAddr + TXwptr);
- break;
- }
+ memcpy_toio(ofs, buffer, len);
+ buffer += len;
if (++pageno == epage)
pageno = spage;
pageofs = 0;
- } while (1);
+ c -= len;
+ }
+ tail = (tail + total) & tx_mask;
}
+ writew(tail, ofsAddr + TXwptr);
writeb(1, ofsAddr + CD180TXirq); /* start to send */
- return (total);
+ return total;
}
-int MoxaPortReadData(int port, struct tty_struct *tty)
+static int MoxaPortReadData(struct moxa_port *port)
{
- register ushort head, pageofs;
- int i, count, cnt, len, total, remain;
- ushort tail, rx_mask, spage, epage;
- ushort pageno, bufhead;
+ struct tty_struct *tty = port->tty;
+ unsigned char *dst;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ unsigned int count, len, total;
+ u16 tail, rx_mask, spage, epage;
+ u16 pageno, pageofs, bufhead, head;
- ofsAddr = moxa_ports[port].tableAddr;
- baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
+ ofsAddr = port->tableAddr;
+ baseAddr = port->board->basemem;
head = readw(ofsAddr + RXrptr);
tail = readw(ofsAddr + RXwptr);
rx_mask = readw(ofsAddr + RX_mask);
spage = readw(ofsAddr + Page_rxb);
epage = readw(ofsAddr + EndPage_rxb);
- count = (tail >= head) ? (tail - head)
- : (tail - head + rx_mask + 1);
+ count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
if (count == 0)
return 0;
total = count;
- remain = count - total;
- moxaLog.rxcnt[port] += total;
- count = total;
+ moxaLog.rxcnt[tty->index] += total;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_rxb);
writew(spage, baseAddr + Control_reg);
while (count > 0) {
- if (tail >= head)
- len = tail - head;
- else
- len = rx_mask + 1 - head;
- len = (count > len) ? len : count;
ofs = baseAddr + DynPage_addr + bufhead + head;
- for (i = 0; i < len; i++)
- tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
+ len = (tail >= head) ? (tail - head) :
+ (rx_mask + 1 - head);
+ len = tty_prepare_flip_string(tty, &dst,
+ min(len, count));
+ memcpy_fromio(dst, ofs, len);
head = (head + len) & rx_mask;
count -= len;
}
- writew(head, ofsAddr + RXrptr);
} else {
- len = count;
pageno = spage + (head >> 13);
pageofs = head & Page_mask;
- do {
- cnt = Page_size - pageofs;
- if (cnt > count)
- cnt = count;
- count -= cnt;
+ while (count > 0) {
writew(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
- for (i = 0; i < cnt; i++)
- tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
- if (count == 0) {
- writew((head + len) & rx_mask, ofsAddr + RXrptr);
- break;
- }
- if (++pageno == epage)
+ len = tty_prepare_flip_string(tty, &dst,
+ min(Page_size - pageofs, count));
+ memcpy_fromio(dst, ofs, len);
+
+ count -= len;
+ pageofs = (pageofs + len) & Page_mask;
+ if (pageofs == 0 && ++pageno == epage)
pageno = spage;
- pageofs = 0;
- } while (1);
+ }
+ head = (head + total) & rx_mask;
}
- if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
+ writew(head, ofsAddr + RXrptr);
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
moxaLowWaterChk = 1;
- moxa_ports[port].lowChkFlag = 1;
+ port->lowChkFlag = 1;
}
- return (total);
+ return total;
}
-int MoxaPortTxQueue(int port)
+static int MoxaPortTxQueue(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
- len = (wptr - rptr) & mask;
- return (len);
+ return (wptr - rptr) & mask;
}
-int MoxaPortTxFree(int port)
+static int MoxaPortTxFree(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
- len = mask - ((wptr - rptr) & mask);
- return (len);
+ return mask - ((wptr - rptr) & mask);
}
-int MoxaPortRxQueue(int port)
+static int MoxaPortRxQueue(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + RXrptr);
wptr = readw(ofsAddr + RXwptr);
mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- return (len);
+ return (wptr - rptr) & mask;
}
-
-void MoxaPortTxDisable(int port)
+static void MoxaPortTxDisable(struct moxa_port *port)
{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
+ moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
}
-void MoxaPortTxEnable(int port)
+static void MoxaPortTxEnable(struct moxa_port *port)
{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- moxafunc(ofsAddr, FC_SetXonState, Magic_code);
-}
-
-
-int MoxaPortResetBrkCnt(int port)
-{
- ushort cnt;
- cnt = moxa_ports[port].breakCnt;
- moxa_ports[port].breakCnt = 0;
- return (cnt);
-}
-
-
-void MoxaPortSendBreak(int port, int ms100)
-{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- if (ms100) {
- moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- msleep(ms100 * 10);
- } else {
- moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- msleep(250);
- }
- moxafunc(ofsAddr, FC_StopBreak, Magic_code);
+ moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
}
static int moxa_get_serial_info(struct moxa_port *info,
- struct serial_struct __user *retinfo)
+ struct serial_struct __user *retinfo)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->port;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.flags = info->asyncflags;
- tmp.baud_base = 921600;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = 0;
- tmp.hub6 = 0;
- if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return (0);
+ struct serial_struct tmp = {
+ .type = info->type,
+ .line = info->tty->index,
+ .flags = info->asyncflags,
+ .baud_base = 921600,
+ .close_delay = info->close_delay
+ };
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
static int moxa_set_serial_info(struct moxa_port *info,
- struct serial_struct __user *new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
- if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- if ((new_serial.irq != 0) ||
- (new_serial.port != 0) ||
-// (new_serial.type != info->type) ||
- (new_serial.custom_divisor != 0) ||
- (new_serial.baud_base != 921600))
- return (-EPERM);
+ if (new_serial.irq != 0 || new_serial.port != 0 ||
+ new_serial.custom_divisor != 0 ||
+ new_serial.baud_base != 921600)
+ return -EPERM;
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->asyncflags & ~ASYNC_USR_MASK)))
- return (-EPERM);
- } else {
+ return -EPERM;
+ } else
info->close_delay = new_serial.close_delay * HZ / 100;
- info->closing_wait = new_serial.closing_wait * HZ / 100;
- }
new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
- if (new_serial.type == PORT_16550A) {
- MoxaSetFifo(info->port, 1);
- } else {
- MoxaSetFifo(info->port, 0);
- }
+ MoxaSetFifo(info, new_serial.type == PORT_16550A);
info->type = new_serial.type;
- return (0);
+ return 0;
}
@@ -2472,374 +2167,10 @@ static int moxa_set_serial_info(struct moxa_port *info,
/*****************************************************************************
* Static local functions: *
*****************************************************************************/
-static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
-{
-
- writew(arg, ofsAddr + FuncArg);
- writew(cmd, ofsAddr + FuncCode);
- moxa_wait_finish(ofsAddr);
-}
-
-static void moxa_wait_finish(void __iomem *ofsAddr)
-{
- unsigned long i, j;
-
- i = jiffies;
- while (readw(ofsAddr + FuncCode) != 0) {
- j = jiffies;
- if ((j - i) > moxaFuncTout) {
- return;
- }
- }
-}
-
-static void moxa_low_water_check(void __iomem *ofsAddr)
-{
- int len;
- ushort rptr, wptr, mask;
-
- if (readb(ofsAddr + FlagStat) & Xoff_state) {
- rptr = readw(ofsAddr + RXrptr);
- wptr = readw(ofsAddr + RXwptr);
- mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- if (len <= Low_water)
- moxafunc(ofsAddr, FC_SendXon, 0);
- }
-}
-
-static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr;
- int i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- writeb(HW_reset, baseAddr + Control_reg); /* reset */
- msleep(10);
- for (i = 0; i < 4096; i++)
- writeb(0, baseAddr + i); /* clear fix page */
- for (i = 0; i < len; i++)
- writeb(moxaBuff[i], baseAddr + i); /* download BIOS */
- writeb(0, baseAddr + Control_reg); /* restart */
- return (0);
-}
-
-static int moxafindcard(int cardno)
-{
- void __iomem *baseAddr;
- ushort tmp;
-
- baseAddr = moxa_boards[cardno].basemem;
- switch (moxa_boards[cardno].boardType) {
- case MOXA_BOARD_C218_ISA:
- case MOXA_BOARD_C218_PCI:
- if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) {
- return (-1);
- }
- break;
- case MOXA_BOARD_CP204J:
- if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) {
- return (-1);
- }
- break;
- default:
- if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) {
- return (-1);
- }
- if ((tmp = readw(baseAddr + C320_status)) != STS_init) {
- return (-2);
- }
- }
- return (0);
-}
-
-static int moxaload320b(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr;
- int i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- 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++)
- writeb(moxaBuff[i], baseAddr + DynPage_addr + i);
- writeb(2, baseAddr + Control_reg); /* Select Page 2 */
- for (i = 0; i < (len - 7168); i++)
- writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i);
- return (0);
-}
-
-static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr, *ofsAddr;
- int retval, port, i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- switch (moxa_boards[cardno].boardType) {
- case MOXA_BOARD_C218_ISA:
- case MOXA_BOARD_C218_PCI:
- case MOXA_BOARD_CP204J:
- retval = moxaloadc218(cardno, baseAddr, len);
- if (retval)
- return (retval);
- port = cardno * MAX_PORTS_PER_BOARD;
- for (i = 0; i < moxa_boards[cardno].numPorts; i++, 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);
- writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
-
- writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
-
- }
- break;
- default:
- retval = moxaloadc320(cardno, baseAddr, len,
- &moxa_boards[cardno].numPorts);
- if (retval)
- return (retval);
- port = cardno * MAX_PORTS_PER_BOARD;
- for (i = 0; i < moxa_boards[cardno].numPorts; i++, 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);
- writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
-
- } else if (moxa_boards[cardno].numPorts == 16) {
- writew(C320p16rx_mask, ofsAddr + RX_mask);
- writew(C320p16tx_mask, ofsAddr + TX_mask);
- writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
-
- } else if (moxa_boards[cardno].numPorts == 24) {
- writew(C320p24rx_mask, ofsAddr + RX_mask);
- writew(C320p24tx_mask, ofsAddr + TX_mask);
- writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- } else if (moxa_boards[cardno].numPorts == 32) {
- writew(C320p32rx_mask, ofsAddr + RX_mask);
- writew(C320p32tx_mask, ofsAddr + TX_mask);
- writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
- writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
- writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
- writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- }
- }
- break;
- }
- moxa_boards[cardno].loadstat = 1;
- return (0);
-}
-
-static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
-{
- char retry;
- int i, j, len1, len2;
- ushort usum, *ptr, keycode;
-
- if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J)
- keycode = CP204J_KeyCode;
- else
- keycode = C218_KeyCode;
- usum = 0;
- len1 = len >> 1;
- ptr = (ushort *) moxaBuff;
- for (i = 0; i < len1; i++)
- usum += le16_to_cpu(*(ptr + i));
- retry = 0;
- do {
- len1 = len >> 1;
- j = 0;
- while (len1) {
- len2 = (len1 > 2048) ? 2048 : len1;
- len1 -= len2;
- for (i = 0; i < len2 << 1; i++)
- writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i);
- j += i;
-
- writew(len2, baseAddr + C218DLoad_len);
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + C218_key) == keycode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + C218_key) != keycode) {
- return (-1);
- }
- }
- writew(0, baseAddr + C218DLoad_len);
- writew(usum, baseAddr + C218check_sum);
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + C218_key) == keycode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + C218chksum_ok) != 1) {
- return (-1);
- }
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code) {
- return (-1);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code) {
- return (-1);
- }
- moxaCard = 1;
- moxa_boards[cardno].intNdx = baseAddr + IRQindex;
- moxa_boards[cardno].intPend = baseAddr + IRQpending;
- moxa_boards[cardno].intTable = baseAddr + IRQtable;
- return (0);
-}
-
-static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPorts)
-{
- ushort usum;
- int i, j, wlen, len2, retry;
- ushort *uptr;
-
- usum = 0;
- wlen = len >> 1;
- uptr = (ushort *) moxaBuff;
- for (i = 0; i < wlen; i++)
- usum += le16_to_cpu(uptr[i]);
- retry = 0;
- j = 0;
- do {
- while (wlen) {
- if (wlen > 2048)
- len2 = 2048;
- else
- len2 = wlen;
- wlen -= len2;
- len2 <<= 1;
- for (i = 0; i < len2; i++)
- writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i);
- len2 >>= 1;
- j += i;
- writew(len2, baseAddr + C320DLoad_len);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 10; i++) {
- if (readw(baseAddr + C320_key) == C320_KeyCode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + C320_key) != C320_KeyCode)
- return (-1);
- }
- writew(0, baseAddr + C320DLoad_len);
- writew(usum, baseAddr + C320check_sum);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 10; i++) {
- if (readw(baseAddr + C320_key) == C320_KeyCode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + C320chksum_ok) != 1)
- return (-1);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-100);
-
- if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
- writew(0x3800, baseAddr + TMS320_PORT1);
- writew(0x3900, baseAddr + TMS320_PORT2);
- writew(28499, baseAddr + TMS320_CLOCK);
- } else {
- writew(0x3200, baseAddr + TMS320_PORT1);
- writew(0x3400, baseAddr + TMS320_PORT2);
- writew(19999, baseAddr + TMS320_CLOCK);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 500; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-102);
-
- j = readw(baseAddr + Module_cnt);
- if (j <= 0)
- return (-101);
- *numPorts = j * 8;
- writew(j, baseAddr + Module_no);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-102);
- moxaCard = 1;
- moxa_boards[cardno].intNdx = baseAddr + IRQindex;
- moxa_boards[cardno].intPend = baseAddr + IRQpending;
- moxa_boards[cardno].intTable = baseAddr + IRQtable;
- return (0);
-}
-static void MoxaSetFifo(int port, int enable)
+static void MoxaSetFifo(struct moxa_port *port, int enable)
{
- void __iomem *ofsAddr = moxa_ports[port].tableAddr;
+ void __iomem *ofsAddr = port->tableAddr;
if (!enable) {
moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
diff --git a/drivers/char/moxa.h b/drivers/char/moxa.h
new file mode 100644
index 000000000000..87d16ce57be7
--- /dev/null
+++ b/drivers/char/moxa.h
@@ -0,0 +1,304 @@
+#ifndef MOXA_H_FILE
+#define MOXA_H_FILE
+
+#define MOXA 0x400
+#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
+#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_IOQUEUE (MOXA + 27)
+#define MOXA_FLUSH_QUEUE (MOXA + 28)
+#define MOXA_GETMSTATUS (MOXA + 65)
+
+/*
+ * System Configuration
+ */
+
+#define Magic_code 0x404
+
+/*
+ * for C218 BIOS initialization
+ */
+#define C218_ConfBase 0x800
+#define C218_status (C218_ConfBase + 0) /* BIOS running status */
+#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
+#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
+#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
+#define C218check_sum (C218_ConfBase + 8) /* BYTE */
+#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
+#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
+#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
+#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
+#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
+
+#define C218_LoadBuf 0x0F00
+#define C218_KeyCode 0x218
+#define CP204J_KeyCode 0x204
+
+/*
+ * for C320 BIOS initialization
+ */
+#define C320_ConfBase 0x800
+#define C320_LoadBuf 0x0f00
+#define STS_init 0x05 /* for C320_status */
+
+#define C320_status C320_ConfBase + 0 /* BIOS running status */
+#define C320_diag C320_ConfBase + 2 /* diagnostic status */
+#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
+#define C320DLoad_len C320_ConfBase + 6 /* WORD */
+#define C320check_sum C320_ConfBase + 8 /* WORD */
+#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
+#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
+#define C320UART_no C320_ConfBase + 0x0e /* WORD */
+
+#define C320_KeyCode 0x320
+
+#define FixPage_addr 0x0000 /* starting addr of static page */
+#define DynPage_addr 0x2000 /* starting addr of dynamic page */
+#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
+#define Control_reg 0x1ff0 /* select page and reset control */
+#define HW_reset 0x80
+
+/*
+ * Function Codes
+ */
+#define FC_CardReset 0x80
+#define FC_ChannelReset 1 /* C320 firmware not supported */
+#define FC_EnableCH 2
+#define FC_DisableCH 3
+#define FC_SetParam 4
+#define FC_SetMode 5
+#define FC_SetRate 6
+#define FC_LineControl 7
+#define FC_LineStatus 8
+#define FC_XmitControl 9
+#define FC_FlushQueue 10
+#define FC_SendBreak 11
+#define FC_StopBreak 12
+#define FC_LoopbackON 13
+#define FC_LoopbackOFF 14
+#define FC_ClrIrqTable 15
+#define FC_SendXon 16
+#define FC_SetTermIrq 17 /* C320 firmware not supported */
+#define FC_SetCntIrq 18 /* C320 firmware not supported */
+#define FC_SetBreakIrq 19
+#define FC_SetLineIrq 20
+#define FC_SetFlowCtl 21
+#define FC_GenIrq 22
+#define FC_InCD180 23
+#define FC_OutCD180 24
+#define FC_InUARTreg 23
+#define FC_OutUARTreg 24
+#define FC_SetXonXoff 25
+#define FC_OutCD180CCR 26
+#define FC_ExtIQueue 27
+#define FC_ExtOQueue 28
+#define FC_ClrLineIrq 29
+#define FC_HWFlowCtl 30
+#define FC_GetClockRate 35
+#define FC_SetBaud 36
+#define FC_SetDataMode 41
+#define FC_GetCCSR 43
+#define FC_GetDataError 45
+#define FC_RxControl 50
+#define FC_ImmSend 51
+#define FC_SetXonState 52
+#define FC_SetXoffState 53
+#define FC_SetRxFIFOTrig 54
+#define FC_SetTxFIFOCnt 55
+#define FC_UnixRate 56
+#define FC_UnixResetTimer 57
+
+#define RxFIFOTrig1 0
+#define RxFIFOTrig4 1
+#define RxFIFOTrig8 2
+#define RxFIFOTrig14 3
+
+/*
+ * Dual-Ported RAM
+ */
+#define DRAM_global 0
+#define INT_data (DRAM_global + 0)
+#define Config_base (DRAM_global + 0x108)
+
+#define IRQindex (INT_data + 0)
+#define IRQpending (INT_data + 4)
+#define IRQtable (INT_data + 8)
+
+/*
+ * Interrupt Status
+ */
+#define IntrRx 0x01 /* receiver data O.K. */
+#define IntrTx 0x02 /* transmit buffer empty */
+#define IntrFunc 0x04 /* function complete */
+#define IntrBreak 0x08 /* received break */
+#define IntrLine 0x10 /* line status change
+ for transmitter */
+#define IntrIntr 0x20 /* received INTR code */
+#define IntrQuit 0x40 /* received QUIT code */
+#define IntrEOF 0x80 /* received EOF code */
+
+#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
+#define IntrTxTrigger 0x200 /* tx data count below trigger value */
+
+#define Magic_no (Config_base + 0)
+#define Card_model_no (Config_base + 2)
+#define Total_ports (Config_base + 4)
+#define Module_cnt (Config_base + 8)
+#define Module_no (Config_base + 10)
+#define Timer_10ms (Config_base + 14)
+#define Disable_IRQ (Config_base + 20)
+#define TMS320_PORT1 (Config_base + 22)
+#define TMS320_PORT2 (Config_base + 24)
+#define TMS320_CLOCK (Config_base + 26)
+
+/*
+ * DATA BUFFER in DRAM
+ */
+#define Extern_table 0x400 /* Base address of the external table
+ (24 words * 64) total 3K bytes
+ (24 words * 128) total 6K bytes */
+#define Extern_size 0x60 /* 96 bytes */
+#define RXrptr 0x00 /* read pointer for RX buffer */
+#define RXwptr 0x02 /* write pointer for RX buffer */
+#define TXrptr 0x04 /* read pointer for TX buffer */
+#define TXwptr 0x06 /* write pointer for TX buffer */
+#define HostStat 0x08 /* IRQ flag and general flag */
+#define FlagStat 0x0A
+#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
+ /* x x x x | | | | */
+ /* | | | + CTS flow */
+ /* | | +--- RTS flow */
+ /* | +------ TX Xon/Xoff */
+ /* +--------- RX Xon/Xoff */
+#define Break_cnt 0x0E /* received break count */
+#define CD180TXirq 0x10 /* if non-0: enable TX irq */
+#define RX_mask 0x12
+#define TX_mask 0x14
+#define Ofs_rxb 0x16
+#define Ofs_txb 0x18
+#define Page_rxb 0x1A
+#define Page_txb 0x1C
+#define EndPage_rxb 0x1E
+#define EndPage_txb 0x20
+#define Data_error 0x22
+#define RxTrigger 0x28
+#define TxTrigger 0x2a
+
+#define rRXwptr 0x34
+#define Low_water 0x36
+
+#define FuncCode 0x40
+#define FuncArg 0x42
+#define FuncArg1 0x44
+
+#define C218rx_size 0x2000 /* 8K bytes */
+#define C218tx_size 0x8000 /* 32K bytes */
+
+#define C218rx_mask (C218rx_size - 1)
+#define C218tx_mask (C218tx_size - 1)
+
+#define C320p8rx_size 0x2000
+#define C320p8tx_size 0x8000
+#define C320p8rx_mask (C320p8rx_size - 1)
+#define C320p8tx_mask (C320p8tx_size - 1)
+
+#define C320p16rx_size 0x2000
+#define C320p16tx_size 0x4000
+#define C320p16rx_mask (C320p16rx_size - 1)
+#define C320p16tx_mask (C320p16tx_size - 1)
+
+#define C320p24rx_size 0x2000
+#define C320p24tx_size 0x2000
+#define C320p24rx_mask (C320p24rx_size - 1)
+#define C320p24tx_mask (C320p24tx_size - 1)
+
+#define C320p32rx_size 0x1000
+#define C320p32tx_size 0x1000
+#define C320p32rx_mask (C320p32rx_size - 1)
+#define C320p32tx_mask (C320p32tx_size - 1)
+
+#define Page_size 0x2000U
+#define Page_mask (Page_size - 1)
+#define C218rx_spage 3
+#define C218tx_spage 4
+#define C218rx_pageno 1
+#define C218tx_pageno 4
+#define C218buf_pageno 5
+
+#define C320p8rx_spage 3
+#define C320p8tx_spage 4
+#define C320p8rx_pgno 1
+#define C320p8tx_pgno 4
+#define C320p8buf_pgno 5
+
+#define C320p16rx_spage 3
+#define C320p16tx_spage 4
+#define C320p16rx_pgno 1
+#define C320p16tx_pgno 2
+#define C320p16buf_pgno 3
+
+#define C320p24rx_spage 3
+#define C320p24tx_spage 4
+#define C320p24rx_pgno 1
+#define C320p24tx_pgno 1
+#define C320p24buf_pgno 2
+
+#define C320p32rx_spage 3
+#define C320p32tx_ofs C320p32rx_size
+#define C320p32tx_spage 3
+#define C320p32buf_pgno 1
+
+/*
+ * Host Status
+ */
+#define WakeupRx 0x01
+#define WakeupTx 0x02
+#define WakeupBreak 0x08
+#define WakeupLine 0x10
+#define WakeupIntr 0x20
+#define WakeupQuit 0x40
+#define WakeupEOF 0x80 /* used in VTIME control */
+#define WakeupRxTrigger 0x100
+#define WakeupTxTrigger 0x200
+/*
+ * Flag status
+ */
+#define Rx_over 0x01
+#define Xoff_state 0x02
+#define Tx_flowOff 0x04
+#define Tx_enable 0x08
+#define CTS_state 0x10
+#define DSR_state 0x20
+#define DCD_state 0x80
+/*
+ * FlowControl
+ */
+#define CTS_FlowCtl 1
+#define RTS_FlowCtl 2
+#define Tx_FlowCtl 4
+#define Rx_FlowCtl 8
+#define IXM_IXANY 0x10
+
+#define LowWater 128
+
+#define DTR_ON 1
+#define RTS_ON 2
+#define CTS_ON 1
+#define DSR_ON 2
+#define DCD_ON 8
+
+/* mode definition */
+#define MX_CS8 0x03
+#define MX_CS7 0x02
+#define MX_CS6 0x01
+#define MX_CS5 0x00
+
+#define MX_STOP1 0x00
+#define MX_STOP15 0x04
+#define MX_STOP2 0x08
+
+#define MX_PARNONE 0x00
+#define MX_PAREVEN 0x40
+#define MX_PARODD 0xC0
+
+#endif
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index ff146c2b08fd..fe2a95b5d3c0 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -180,7 +180,7 @@ mspec_close(struct vm_area_struct *vma)
my_page = vdata->maddr[index];
vdata->maddr[index] = 0;
if (!mspec_zero_block(my_page, PAGE_SIZE))
- uncached_free_page(my_page);
+ uncached_free_page(my_page, 1);
else
printk(KERN_WARNING "mspec_close(): "
"failed to zero page %ld\n", my_page);
@@ -209,7 +209,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
index = (address - vdata->vm_start) >> PAGE_SHIFT;
maddr = (volatile unsigned long) vdata->maddr[index];
if (maddr == 0) {
- maddr = uncached_alloc_page(numa_node_id());
+ maddr = uncached_alloc_page(numa_node_id(), 1);
if (maddr == 0)
return NOPFN_OOM;
@@ -218,7 +218,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
vdata->count++;
vdata->maddr[index] = maddr;
} else {
- uncached_free_page(maddr);
+ uncached_free_page(maddr, 1);
maddr = vdata->maddr[index];
}
spin_unlock(&vdata->lock);
@@ -367,7 +367,7 @@ mspec_init(void)
int nasid;
unsigned long phys;
- scratch_page[nid] = uncached_alloc_page(nid);
+ scratch_page[nid] = uncached_alloc_page(nid, 1);
if (scratch_page[nid] == 0)
goto free_scratch_pages;
phys = __pa(scratch_page[nid]);
@@ -414,7 +414,7 @@ mspec_init(void)
free_scratch_pages:
for_each_node(nid) {
if (scratch_page[nid] != 0)
- uncached_free_page(scratch_page[nid]);
+ uncached_free_page(scratch_page[nid], 1);
}
return ret;
}
@@ -431,7 +431,7 @@ mspec_exit(void)
for_each_node(nid) {
if (scratch_page[nid] != 0)
- uncached_free_page(scratch_page[nid]);
+ uncached_free_page(scratch_page[nid], 1);
}
}
}
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 68c2e9234691..4b81a85c5b53 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -307,6 +307,200 @@ 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 void mxser_enable_must_enchance_mode(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void mxser_disable_must_enchance_mode(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 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(value, baseio + MOXA_MUST_XON1_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 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(value, baseio + MOXA_MUST_XOFF1_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_fifo_value(struct mxser_port *info)
+{
+ u8 oldlcr;
+ u8 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;
+
+ 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);
+}
+
+static void mxser_set_must_enum_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 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);
+ outb(value, baseio + MOXA_MUST_ENUM_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void mxser_enable_must_tx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void mxser_disable_must_tx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void mxser_enable_must_rx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
+static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 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);
+}
+
#ifdef CONFIG_PCI
static int __devinit CheckIsMoxaMust(unsigned long io)
{
@@ -314,16 +508,16 @@ static int __devinit CheckIsMoxaMust(unsigned long io)
int i;
outb(0, io + UART_LCR);
- DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
+ mxser_disable_must_enchance_mode(io);
oldmcr = inb(io + UART_MCR);
outb(0, io + UART_MCR);
- SET_MOXA_MUST_XON1_VALUE(io, 0x11);
+ mxser_set_must_xon1_value(io, 0x11);
if ((hwid = inb(io + UART_MCR)) != 0) {
outb(oldmcr, io + UART_MCR);
return MOXA_OTHER_UART;
}
- GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
+ mxser_get_must_hardware_id(io, &hwid);
for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
if (hwid == Gpci_uart_info[i].type)
return (int)hwid;
@@ -494,10 +688,10 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
} else
quot /= newspd;
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+ mxser_set_must_enum_value(info->ioaddr, quot);
} else
#endif
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
+ mxser_set_must_enum_value(info->ioaddr, 0);
return 0;
}
@@ -553,14 +747,14 @@ static int mxser_change_speed(struct mxser_port *info,
if (info->board->chip_flag) {
fcr = UART_FCR_ENABLE_FIFO;
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
+ mxser_set_must_fifo_value(info);
} else
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
if (info->board->chip_flag) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
+ mxser_set_must_fifo_value(info);
} else {
switch (info->rx_trigger) {
case 1:
@@ -657,17 +851,21 @@ static int mxser_change_speed(struct mxser_port *info,
}
}
if (info->board->chip_flag) {
- SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
- SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+ mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->tty));
+ mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->tty));
if (I_IXON(info->tty)) {
- ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_enable_must_rx_software_flow_control(
+ info->ioaddr);
} else {
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_rx_software_flow_control(
+ info->ioaddr);
}
if (I_IXOFF(info->tty)) {
- ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_enable_must_tx_software_flow_control(
+ info->ioaddr);
} else {
- DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_tx_software_flow_control(
+ info->ioaddr);
}
}
@@ -927,6 +1125,27 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
return 0;
}
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ char fcr;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ fcr = inb(info->ioaddr + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+ outb(fcr, info->ioaddr + UART_FCR);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_wakeup(tty);
+}
+
+
/*
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
@@ -1013,9 +1232,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
mxser_shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
-
+ mxser_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1072,16 +1289,16 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
return total;
}
-static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
if (!info->xmit_buf)
- return;
+ return 0;
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
- return;
+ return 0;
spin_lock_irqsave(&info->slock, flags);
info->xmit_buf[info->xmit_head++] = ch;
@@ -1099,6 +1316,7 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
spin_unlock_irqrestore(&info->slock, flags);
}
}
+ return 1;
}
@@ -1142,26 +1360,6 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
return info->xmit_cnt;
}
-static void mxser_flush_buffer(struct tty_struct *tty)
-{
- struct mxser_port *info = tty->driver_data;
- char fcr;
- unsigned long flags;
-
-
- spin_lock_irqsave(&info->slock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- fcr = inb(info->ioaddr + UART_FCR);
- outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
- info->ioaddr + UART_FCR);
- outb(fcr, info->ioaddr + UART_FCR);
-
- spin_unlock_irqrestore(&info->slock, flags);
-
- tty_wakeup(tty);
-}
-
/*
* ------------------------------------------------------------
* friends of mxser_ioctl()
@@ -1460,6 +1658,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
struct mxser_port *port;
int result, status;
unsigned int i, j;
+ int ret = 0;
switch (cmd) {
case MOXA_GET_MAJOR:
@@ -1467,18 +1666,21 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
case MOXA_CHKPORTENABLE:
result = 0;
-
+ lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
if (mxser_boards[i].ports[j].ioaddr)
result |= (1 << i);
-
+ unlock_kernel();
return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
+ lock_kernel();
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ unlock_kernel();
+ return ret;
case MOXA_GETMSTATUS:
+ lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
@@ -1515,6 +1717,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
else
GMStatus[i].cts = 0;
}
+ unlock_kernel();
if (copy_to_user(argp, GMStatus,
sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
@@ -1524,7 +1727,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
unsigned long opmode;
unsigned cflag, iflag;
- for (i = 0; i < MXSER_BOARDS; i++)
+ lock_kernel();
+ for (i = 0; i < MXSER_BOARDS; i++) {
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
if (!port->ioaddr)
@@ -1589,13 +1793,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
mon_data_ext.iftype[i] = opmode;
}
- if (copy_to_user(argp, &mon_data_ext,
- sizeof(mon_data_ext)))
- return -EFAULT;
-
- return 0;
-
- } default:
+ }
+ unlock_kernel();
+ if (copy_to_user(argp, &mon_data_ext,
+ sizeof(mon_data_ext)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
return -ENOIOCTLCMD;
}
return 0;
@@ -1651,16 +1856,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
opmode != RS422_MODE &&
opmode != RS485_4WIRE_MODE)
return -EFAULT;
+ lock_kernel();
mask = ModeMask[p];
shiftbit = p * 2;
val = inb(info->opmode_ioaddr);
val &= mask;
val |= (opmode << shiftbit);
outb(val, info->opmode_ioaddr);
+ unlock_kernel();
} else {
+ lock_kernel();
shiftbit = p * 2;
opmode = inb(info->opmode_ioaddr) >> shiftbit;
opmode &= OP_MODE_MASK;
+ unlock_kernel();
if (put_user(opmode, (int __user *)argp))
return -EFAULT;
}
@@ -1687,19 +1896,18 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
tty_wait_until_sent(tty, 0);
mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
return 0;
- case TIOCGSOFTCAR:
- return put_user(!!C_CLOCAL(tty), (unsigned long __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
- return mxser_get_serial_info(info, argp);
+ lock_kernel();
+ retval = mxser_get_serial_info(info, argp);
+ unlock_kernel();
+ return retval;
case TIOCSSERIAL:
- return mxser_set_serial_info(info, argp);
+ lock_kernel();
+ retval = mxser_set_serial_info(info, argp);
+ unlock_kernel();
+ return retval;
case TIOCSERGETLSR: /* Get line status register */
- return mxser_get_lsr_info(info, argp);
+ return mxser_get_lsr_info(info, argp);
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -1746,24 +1954,27 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
case MOXA_HighSpeedOn:
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
case MOXA_SDS_RSTICOUNTER:
+ lock_kernel();
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
+ unlock_kernel();
return 0;
case MOXA_ASPP_OQUEUE:{
int len, lsr;
+ lock_kernel();
len = mxser_chars_in_buffer(tty);
-
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
-
len += (lsr ? 0 : 1);
+ unlock_kernel();
return put_user(len, (int __user *)argp);
}
case MOXA_ASPP_MON: {
int mcr, status;
+ lock_kernel();
status = mxser_get_msr(info->ioaddr, 1, tty->index);
mxser_check_modem_status(info, status);
@@ -1782,7 +1993,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
+ unlock_kernel();
if (copy_to_user(argp, &info->mon_data,
sizeof(struct mxser_mon)))
return -EFAULT;
@@ -1925,7 +2136,8 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
if (info->board->chip_flag) {
spin_lock_irqsave(&info->slock, flags);
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_rx_software_flow_control(
+ info->ioaddr);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -1979,6 +2191,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
+ lock_kernel();
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
@@ -1990,6 +2203,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
@@ -2342,7 +2556,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
/* Enhance mode enabled here */
if (brd->chip_flag != MOXA_OTHER_UART)
- ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+ mxser_enable_must_enchance_mode(info->ioaddr);
info->flags = ASYNC_SHARE_IRQ;
info->type = brd->uart_type;
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
index 844171115954..41878a69203d 100644
--- a/drivers/char/mxser.h
+++ b/drivers/char/mxser.h
@@ -147,141 +147,4 @@
/* Rx software flow control mask */
#define MOXA_MUST_EFR_SF_RX_MASK 0x03
-#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); \
-} 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); \
-} 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); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#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_XOFF1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#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; \
- 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); \
-} 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); \
- outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#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_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_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; \
- __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_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); \
-} 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); \
-} while (0)
-
#endif
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 06803ed5568c..a35bfd7ee80e 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -342,12 +342,10 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
#endif
/* Flush any pending characters in the driver and discipline. */
-
if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
+ tty->ldisc.flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer (tty);
+ tty_driver_flush_buffer(tty);
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
@@ -399,7 +397,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* Send the next block of data to device */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = tty->driver->write(tty, tbuf->buf, tbuf->count);
+ actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
/* rollback was possible and has been done */
if (actual == -ERESTARTSYS) {
@@ -578,26 +576,36 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
return -EFAULT;
}
+ lock_kernel();
+
for (;;) {
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+ unlock_kernel();
return -EIO;
+ }
n_hdlc = tty2n_hdlc (tty);
if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
- tty != n_hdlc->tty)
+ tty != n_hdlc->tty) {
+ unlock_kernel();
return 0;
+ }
rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
if (rbuf)
break;
/* no data */
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK) {
+ unlock_kernel();
return -EAGAIN;
+ }
interruptible_sleep_on (&tty->read_wait);
- if (signal_pending(current))
+ if (signal_pending(current)) {
+ unlock_kernel();
return -EINTR;
+ }
}
if (rbuf->count > nr)
@@ -618,7 +626,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
kfree(rbuf);
else
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-
+ unlock_kernel();
return ret;
} /* end of n_hdlc_tty_read() */
@@ -661,6 +669,8 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
count = maxframe;
}
+ lock_kernel();
+
add_wait_queue(&tty->write_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -695,7 +705,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
n_hdlc_send_frames(n_hdlc,tty);
}
-
+ unlock_kernel();
return error;
} /* end of n_hdlc_tty_write() */
@@ -740,8 +750,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
case TIOCOUTQ:
/* get the pending tx byte count in the driver */
- count = tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0;
+ count = tty_chars_in_buffer(tty);
/* add size of next output frame in queue */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
if (n_hdlc->tx_buf_list.head)
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 6b918b80f73e..902169062332 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -376,8 +376,9 @@ static void put_char(struct r3964_info *pInfo, unsigned char ch)
if (tty == NULL)
return;
- if (tty->driver->put_char) {
- tty->driver->put_char(tty, ch);
+ /* FIXME: put_char should not be called from an IRQ */
+ if (tty->ops->put_char) {
+ tty->ops->put_char(tty, ch);
}
pInfo->bcc ^= ch;
}
@@ -386,12 +387,9 @@ static void flush(struct r3964_info *pInfo)
{
struct tty_struct *tty = pInfo->tty;
- if (tty == NULL)
+ if (tty == NULL || tty->ops->flush_chars == NULL)
return;
-
- if (tty->driver->flush_chars) {
- tty->driver->flush_chars(tty);
- }
+ tty->ops->flush_chars(tty);
}
static void trigger_transmit(struct r3964_info *pInfo)
@@ -449,12 +447,11 @@ static void transmit_block(struct r3964_info *pInfo)
struct r3964_block_header *pBlock = pInfo->tx_first;
int room = 0;
- if ((tty == NULL) || (pBlock == NULL)) {
+ if (tty == NULL || pBlock == NULL) {
return;
}
- if (tty->driver->write_room)
- room = tty->driver->write_room(tty);
+ room = tty_write_room(tty);
TRACE_PS("transmit_block %p, room %d, length %d",
pBlock, room, pBlock->length);
@@ -1075,12 +1072,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
+ lock_kernel();
+
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) {
+ unlock_kernel();
return -EAGAIN;
}
/* block until there is a message: */
@@ -1090,8 +1090,10 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
/* If we still haven't got a message, we must have been signalled */
- if (!pMsg)
+ if (!pMsg) {
+ unlock_kernel();
return -EINTR;
+ }
/* deliver msg to client process: */
theMsg.msg_id = pMsg->msg_id;
@@ -1102,12 +1104,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
kfree(pMsg);
TRACE_M("r3964_read - msg kfree %p", pMsg);
- if (copy_to_user(buf, &theMsg, count))
+ if (copy_to_user(buf, &theMsg, count)) {
+ unlock_kernel();
return -EFAULT;
+ }
TRACE_PS("read - return %d", count);
return count;
}
+ unlock_kernel();
return -EPERM;
}
@@ -1156,6 +1161,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
+ lock_kernel();
+
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
pHeader->owner = pClient;
@@ -1173,6 +1180,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
+ unlock_kernel();
+
return 0;
}
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 0c09409fa45d..8096389b0dc2 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -147,10 +147,8 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty)
static void check_unthrottle(struct tty_struct *tty)
{
- if (tty->count &&
- test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ if (tty->count)
+ tty_unthrottle(tty);
}
/**
@@ -183,22 +181,24 @@ static void reset_buffer_flags(struct tty_struct *tty)
* at hangup) or when the N_TTY line discipline internally has to
* clean the pending queue (for example some signals).
*
- * FIXME: tty->ctrl_status is not spinlocked and relies on
- * lock_kernel() still.
+ * Locking: ctrl_lock
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
{
+ unsigned long flags;
/* clear everything and unthrottle the driver */
reset_buffer_flags(tty);
if (!tty->link)
return;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
}
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
/**
@@ -264,33 +264,38 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty)
* relevant in the world today. If you ever need them, add them here.
*
* Called from both the receive and transmit sides and can be called
- * re-entrantly. Relies on lock_kernel() still.
+ * re-entrantly. Relies on lock_kernel() for tty->column state.
*/
static int opost(unsigned char c, struct tty_struct *tty)
{
int space, spaces;
- space = tty->driver->write_room(tty);
+ space = tty_write_room(tty);
if (!space)
return -1;
+ lock_kernel();
if (O_OPOST(tty)) {
switch (c) {
case '\n':
if (O_ONLRET(tty))
tty->column = 0;
if (O_ONLCR(tty)) {
- if (space < 2)
+ if (space < 2) {
+ unlock_kernel();
return -1;
- tty->driver->put_char(tty, '\r');
+ }
+ tty_put_char(tty, '\r');
tty->column = 0;
}
tty->canon_column = tty->column;
break;
case '\r':
- if (O_ONOCR(tty) && tty->column == 0)
+ if (O_ONOCR(tty) && tty->column == 0) {
+ unlock_kernel();
return 0;
+ }
if (O_OCRNL(tty)) {
c = '\n';
if (O_ONLRET(tty))
@@ -302,10 +307,13 @@ static int opost(unsigned char c, struct tty_struct *tty)
case '\t':
spaces = 8 - (tty->column & 7);
if (O_TABDLY(tty) == XTABS) {
- if (space < spaces)
+ if (space < spaces) {
+ unlock_kernel();
return -1;
+ }
tty->column += spaces;
- tty->driver->write(tty, " ", spaces);
+ tty->ops->write(tty, " ", spaces);
+ unlock_kernel();
return 0;
}
tty->column += spaces;
@@ -322,7 +330,8 @@ static int opost(unsigned char c, struct tty_struct *tty)
break;
}
}
- tty->driver->put_char(tty, c);
+ tty_put_char(tty, c);
+ unlock_kernel();
return 0;
}
@@ -337,7 +346,8 @@ static int opost(unsigned char c, struct tty_struct *tty)
* the simple cases normally found and helps to generate blocks of
* symbols for the console driver and thus improve performance.
*
- * Called from write_chan under the tty layer write lock.
+ * Called from write_chan under the tty layer write lock. Relies
+ * on lock_kernel for the tty->column state.
*/
static ssize_t opost_block(struct tty_struct *tty,
@@ -347,12 +357,13 @@ static ssize_t opost_block(struct tty_struct *tty,
int i;
const unsigned char *cp;
- space = tty->driver->write_room(tty);
+ space = tty_write_room(tty);
if (!space)
return 0;
if (nr > space)
nr = space;
+ lock_kernel();
for (i = 0, cp = buf; i < nr; i++, cp++) {
switch (*cp) {
case '\n':
@@ -384,27 +395,15 @@ static ssize_t opost_block(struct tty_struct *tty,
}
}
break_out:
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
- i = tty->driver->write(tty, buf, i);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
+ i = tty->ops->write(tty, buf, i);
+ unlock_kernel();
return i;
}
/**
- * put_char - write character to driver
- * @c: character (or part of unicode symbol)
- * @tty: terminal device
- *
- * Queue a byte to the driver layer for output
- */
-
-static inline void put_char(unsigned char c, struct tty_struct *tty)
-{
- tty->driver->put_char(tty, c);
-}
-
-/**
* echo_char - echo characters
* @c: unicode byte to echo
* @tty: terminal device
@@ -416,8 +415,8 @@ static inline void put_char(unsigned char c, struct tty_struct *tty)
static void echo_char(unsigned char c, struct tty_struct *tty)
{
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
- put_char('^', tty);
- put_char(c ^ 0100, tty);
+ tty_put_char(tty, '^');
+ tty_put_char(tty, c ^ 0100);
tty->column += 2;
} else
opost(c, tty);
@@ -426,7 +425,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
static inline void finish_erasing(struct tty_struct *tty)
{
if (tty->erasing) {
- put_char('/', tty);
+ tty_put_char(tty, '/');
tty->column++;
tty->erasing = 0;
}
@@ -510,7 +509,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!tty->erasing) {
- put_char('\\', tty);
+ tty_put_char(tty, '\\');
tty->column++;
tty->erasing = 1;
}
@@ -518,7 +517,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
echo_char(c, tty);
while (--cnt > 0) {
head = (head+1) & (N_TTY_BUF_SIZE-1);
- put_char(tty->read_buf[head], tty);
+ tty_put_char(tty, tty->read_buf[head]);
}
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
@@ -546,22 +545,22 @@ static void eraser(unsigned char c, struct tty_struct *tty)
/* Now backup to that column. */
while (tty->column > col) {
/* Can't use opost here. */
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
- put_char('\b', tty);
- put_char(' ', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
+ tty_put_char(tty, ' ');
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
- put_char('\b', tty);
- put_char(' ', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
+ tty_put_char(tty, ' ');
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
@@ -592,8 +591,7 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
}
}
@@ -701,7 +699,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
- c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+ c == INTR_CHAR(tty) || c == QUIT_CHAR(tty) || c == SUSP_CHAR(tty)))
start_tty(tty);
if (tty->closing) {
@@ -725,7 +723,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
tty->lnext = 0;
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
- put_char('\a', tty); /* beep if no space */
+ tty_put_char(tty, '\a'); /* beep if no space */
return;
}
/* Record the column of first canon char. */
@@ -739,13 +737,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
return;
}
- if (c == '\r') {
- if (I_IGNCR(tty))
- return;
- if (I_ICRNL(tty))
- c = '\n';
- } else if (c == '\n' && I_INLCR(tty))
- c = '\r';
if (I_IXON(tty)) {
if (c == START_CHAR(tty)) {
start_tty(tty);
@@ -756,6 +747,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
return;
}
}
+
if (L_ISIG(tty)) {
int signal;
signal = SIGINT;
@@ -775,8 +767,7 @@ send_signal:
*/
if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
}
if (L_ECHO(tty))
echo_char(c, tty);
@@ -785,6 +776,15 @@ send_signal:
return;
}
}
+
+ if (c == '\r') {
+ if (I_IGNCR(tty))
+ return;
+ if (I_ICRNL(tty))
+ c = '\n';
+ } else if (c == '\n' && I_INLCR(tty))
+ c = '\r';
+
if (tty->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
@@ -796,8 +796,8 @@ send_signal:
if (L_ECHO(tty)) {
finish_erasing(tty);
if (L_ECHOCTL(tty)) {
- put_char('^', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '^');
+ tty_put_char(tty, '\b');
}
}
return;
@@ -818,7 +818,7 @@ send_signal:
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
- put_char('\a', tty);
+ tty_put_char(tty, '\a');
opost('\n', tty);
}
goto handle_newline;
@@ -836,7 +836,7 @@ send_signal:
*/
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
- put_char('\a', tty);
+ tty_put_char(tty, '\a');
/* Record the column of first canon char. */
if (tty->canon_head == tty->read_head)
tty->canon_column = tty->column;
@@ -866,7 +866,7 @@ handle_newline:
finish_erasing(tty);
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
- put_char('\a', tty); /* beep if no space */
+ tty_put_char(tty, '\a'); /* beep if no space */
return;
}
if (c == '\n')
@@ -970,8 +970,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
break;
}
}
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
}
n_tty_set_room(tty);
@@ -987,12 +987,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE) {
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->throttle)
- tty->driver->throttle(tty);
- }
+ if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+ tty_throttle(tty);
}
int is_ignored(int sig)
@@ -1076,6 +1072,9 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
tty->real_raw = 0;
}
n_tty_set_room(tty);
+ /* The termios change make the tty ready for I/O */
+ wake_up_interruptible(&tty->write_wait);
+ wake_up_interruptible(&tty->read_wait);
}
/**
@@ -1194,6 +1193,11 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
* Perform job control management checks on this file/tty descriptor
* and if appropriate send any needed signals and return a negative
* error code if action should be taken.
+ *
+ * FIXME:
+ * Locking: None - redirected write test is safe, testing
+ * current->signal should possibly lock current->sighand
+ * pgrp locking ?
*/
static int job_control(struct tty_struct *tty, struct file *file)
@@ -1246,6 +1250,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
ssize_t size;
long timeout;
unsigned long flags;
+ int packet;
do_it_again:
@@ -1289,16 +1294,19 @@ do_it_again:
if (mutex_lock_interruptible(&tty->atomic_read_lock))
return -ERESTARTSYS;
}
+ packet = tty->packet;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
/* First test for status change. */
- if (tty->packet && tty->link->ctrl_status) {
+ if (packet && tty->link->ctrl_status) {
unsigned char cs;
if (b != buf)
break;
+ spin_lock_irqsave(&tty->link->ctrl_lock, flags);
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
+ spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
if (tty_put_user(tty, cs, b++)) {
retval = -EFAULT;
b--;
@@ -1333,6 +1341,7 @@ do_it_again:
retval = -ERESTARTSYS;
break;
}
+ /* FIXME: does n_tty_set_room need locking ? */
n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
continue;
@@ -1340,7 +1349,7 @@ do_it_again:
__set_current_state(TASK_RUNNING);
/* Deal with packet mode. */
- if (tty->packet && b == buf) {
+ if (packet && b == buf) {
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
retval = -EFAULT;
b--;
@@ -1388,6 +1397,8 @@ do_it_again:
break;
} else {
int uncopied;
+ /* The copy function takes the read lock and handles
+ locking internally for this case */
uncopied = copy_from_read_buf(tty, &b, &nr);
uncopied += copy_from_read_buf(tty, &b, &nr);
if (uncopied) {
@@ -1429,7 +1440,6 @@ do_it_again:
goto do_it_again;
n_tty_set_room(tty);
-
return retval;
}
@@ -1492,11 +1502,11 @@ static ssize_t write_chan(struct tty_struct *tty, struct file *file,
break;
b++; nr--;
}
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
} else {
while (nr > 0) {
- c = tty->driver->write(tty, b, nr);
+ c = tty->ops->write(tty, b, nr);
if (c < 0) {
retval = c;
goto break_out;
@@ -1533,11 +1543,6 @@ break_out:
*
* This code must be sure never to sleep through a hangup.
* Called without the kernel lock held - fine
- *
- * FIXME: if someone changes the VMIN or discipline settings for the
- * terminal while another process is in poll() the poll does not
- * recompute the new limits. Possibly set_termios should issue
- * a read wakeup to fix this bug.
*/
static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
@@ -1561,9 +1566,9 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
else
tty->minimum_to_wake = 1;
}
- if (!tty_is_writelocked(tty) &&
- tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS &&
- tty->driver->write_room(tty) > 0)
+ if (tty->ops->write && !tty_is_writelocked(tty) &&
+ tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
+ tty_write_room(tty) > 0)
mask |= POLLOUT | POLLWRNORM;
return mask;
}
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 6a6843a0a674..66a0f931c66c 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -73,7 +73,7 @@ do { \
char tmp[P_BUF_SIZE]; \
snprintf(tmp, sizeof(tmp), ##args); \
printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \
- __FUNCTION__, tmp); \
+ __func__, tmp); \
} while (0)
#define DBG1(args...) D_(0x01, ##args)
@@ -1407,7 +1407,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
/* Find out what card type it is */
nozomi_get_card_type(dc);
- dc->base_addr = ioremap(start, dc->card_type);
+ dc->base_addr = ioremap_nocache(start, dc->card_type);
if (!dc->base_addr) {
dev_err(&pdev->dev, "Unable to map card MMIO\n");
ret = -ENODEV;
@@ -1724,6 +1724,8 @@ static int ntty_tiocmget(struct tty_struct *tty, struct file *file)
const struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
const struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+ /* Note: these could change under us but it is not clear this
+ matters if so */
return (ctrl_ul->RTS ? TIOCM_RTS : 0) |
(ctrl_ul->DTR ? TIOCM_DTR : 0) |
(ctrl_dl->DCD ? TIOCM_CAR : 0) |
@@ -1849,16 +1851,6 @@ static void ntty_throttle(struct tty_struct *tty)
spin_unlock_irqrestore(&dc->spin_mutex, flags);
}
-/* just to discard single character writes */
-static void ntty_put_char(struct tty_struct *tty, unsigned char c)
-{
- /*
- * card does not react correct when we write single chars
- * to the card, so we discard them
- */
- DBG2("PUT CHAR Function: %c", c);
-}
-
/* Returns number of chars in buffer, called by tty layer */
static s32 ntty_chars_in_buffer(struct tty_struct *tty)
{
@@ -1892,7 +1884,6 @@ static const struct tty_operations tty_ops = {
.unthrottle = ntty_unthrottle,
.throttle = ntty_throttle,
.chars_in_buffer = ntty_chars_in_buffer,
- .put_char = ntty_put_char,
.tiocmget = ntty_tiocmget,
.tiocmset = ntty_tiocmset,
};
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 454d7324ba40..4a933d413423 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -53,7 +53,7 @@ module_param(pc_debug, int, 0600);
#define DEBUGP(n, rdr, x, args...) do { \
if (pc_debug >= (n)) \
dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __FUNCTION__ , ## args); \
+ __func__ , ## args); \
} while (0)
#else
#define DEBUGP(n, rdr, x, args...)
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 5f291bf739a6..035084c07329 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -47,7 +47,7 @@ module_param(pc_debug, int, 0600);
#define DEBUGP(n, rdr, x, args...) do { \
if (pc_debug >= (n)) \
dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __FUNCTION__ , ##args); \
+ __func__ , ##args); \
} while (0)
#else
#define DEBUGP(n, rdr, x, args...)
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
index 1f978ff87fa8..fa9d3c945f31 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.c
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -354,32 +354,6 @@ struct ipw_rx_packet {
unsigned int channel_idx;
};
-#ifdef IPWIRELESS_STATE_DEBUG
-int ipwireless_dump_hardware_state(char *p, size_t limit,
- struct ipw_hardware *hw)
-{
- return snprintf(p, limit,
- "debug: initializing=%d\n"
- "debug: tx_ready=%d\n"
- "debug: tx_queued=%d\n"
- "debug: rx_ready=%d\n"
- "debug: rx_bytes_queued=%d\n"
- "debug: blocking_rx=%d\n"
- "debug: removed=%d\n"
- "debug: hardware.shutting_down=%d\n"
- "debug: to_setup=%d\n",
- hw->initializing,
- hw->tx_ready,
- hw->tx_queued,
- hw->rx_ready,
- hw->rx_bytes_queued,
- hw->blocking_rx,
- hw->removed,
- hw->shutting_down,
- hw->to_setup);
-}
-#endif
-
static char *data_type(const unsigned char *buf, unsigned length)
{
struct nl_packet_header *hdr = (struct nl_packet_header *) buf;
diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h
index c83190ffb0e7..19ce5eb266b1 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.h
+++ b/drivers/char/pcmcia/ipwireless/hardware.h
@@ -58,7 +58,5 @@ void ipwireless_init_hardware_v1(struct ipw_hardware *hw,
void *reboot_cb_data);
void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw);
void ipwireless_sleep(unsigned int tenths);
-int ipwireless_dump_hardware_state(char *p, size_t limit,
- struct ipw_hardware *hw);
#endif
diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c
index d793e68b3e0d..fe914d34f7f6 100644
--- a/drivers/char/pcmcia/ipwireless/network.c
+++ b/drivers/char/pcmcia/ipwireless/network.c
@@ -63,21 +63,6 @@ struct ipw_network {
struct work_struct work_go_offline;
};
-
-#ifdef IPWIRELESS_STATE_DEBUG
-int ipwireless_dump_network_state(char *p, size_t limit,
- struct ipw_network *network)
-{
- return snprintf(p, limit,
- "debug: ppp_blocked=%d\n"
- "debug: outgoing_packets_queued=%d\n"
- "debug: network.shutting_down=%d\n",
- network->ppp_blocked,
- network->outgoing_packets_queued,
- network->shutting_down);
-}
-#endif
-
static void notify_packet_sent(void *callback_data, unsigned int packet_length)
{
struct ipw_network *network = callback_data;
diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h
index b0e1e952fd14..ccacd26fc7ef 100644
--- a/drivers/char/pcmcia/ipwireless/network.h
+++ b/drivers/char/pcmcia/ipwireless/network.h
@@ -49,7 +49,4 @@ void ipwireless_ppp_close(struct ipw_network *net);
int ipwireless_ppp_channel_index(struct ipw_network *net);
int ipwireless_ppp_unit_number(struct ipw_network *net);
-int ipwireless_dump_network_state(char *p, size_t limit,
- struct ipw_network *net);
-
#endif
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 583356426dfb..1dd0e992c83d 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -503,20 +503,9 @@ static void* mgslpc_get_text_ptr(void)
* The wrappers maintain line discipline references
* while calling into the line discipline.
*
- * ldisc_flush_buffer - flush line discipline receive buffers
* ldisc_receive_buf - pass receive data to line discipline
*/
-static void ldisc_flush_buffer(struct tty_struct *tty)
-{
- struct tty_ldisc *ld = tty_ldisc_ref(tty);
- if (ld) {
- if (ld->flush_buffer)
- ld->flush_buffer(tty);
- tty_ldisc_deref(ld);
- }
-}
-
static void ldisc_receive_buf(struct tty_struct *tty,
const __u8 *data, char *flags, int count)
{
@@ -1556,7 +1545,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
/* Add a character to the transmit buffer
*/
-static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
+static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
@@ -1567,10 +1556,10 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
}
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
- return;
+ return 0;
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
@@ -1583,6 +1572,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
}
spin_unlock_irqrestore(&info->lock,flags);
+ return 1;
}
/* Enable transmitter so remaining characters in the
@@ -2467,10 +2457,9 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
if (info->flags & ASYNC_INITIALIZED)
mgslpc_wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mgslpc_flush_buffer(tty);
- ldisc_flush_buffer(tty);
+ tty_ldisc_flush(tty);
shutdown(info);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 706ff34728f1..0a05c038ae6f 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -181,6 +181,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user * arg)
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
+ unsigned long flags;
if (!to)
return;
@@ -189,8 +190,10 @@ static void pty_flush_buffer(struct tty_struct *tty)
to->ldisc.flush_buffer(to);
if (to->packet) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
}
@@ -251,6 +254,18 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
module_param(legacy_count, int, 0);
+static const struct tty_operations pty_ops_bsd = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_bsd_ioctl,
+};
+
static void __init legacy_pty_init(void)
{
if (legacy_count <= 0)
@@ -281,7 +296,6 @@ static void __init legacy_pty_init(void)
pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &pty_ops);
- pty_driver->ioctl = pty_bsd_ioctl;
pty_slave_driver->owner = THIS_MODULE;
pty_slave_driver->driver_name = "pty_slave";
@@ -374,6 +388,19 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
+static const struct tty_operations pty_unix98_ops = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_unix98_ioctl
+};
+
+
static void __init unix98_pty_init(void)
{
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
@@ -400,8 +427,7 @@ static void __init unix98_pty_init(void)
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
- tty_set_operations(ptm_driver, &pty_ops);
- ptm_driver->ioctl = pty_unix98_ioctl;
+ tty_set_operations(ptm_driver, &pty_unix98_ops);
pts_driver->owner = THIS_MODULE;
pts_driver->driver_name = "pty_slave";
diff --git a/drivers/char/random.c b/drivers/char/random.c
index f43c89f7c449..0cf98bd4f2d2 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -272,7 +272,7 @@ static int random_write_wakeup_thresh = 128;
static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28;
-static DEFINE_PER_CPU(int, trickle_count) = 0;
+static DEFINE_PER_CPU(int, trickle_count);
/*
* A pool of size .poolwords is stirred with a primitive polynomial
@@ -370,17 +370,19 @@ static struct poolinfo {
*/
static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
+static struct fasync_struct *fasync;
#if 0
-static int debug = 0;
+static int debug;
module_param(debug, bool, 0644);
-#define DEBUG_ENT(fmt, arg...) do { if (debug) \
- printk(KERN_DEBUG "random %04d %04d %04d: " \
- fmt,\
- input_pool.entropy_count,\
- blocking_pool.entropy_count,\
- nonblocking_pool.entropy_count,\
- ## arg); } while (0)
+#define DEBUG_ENT(fmt, arg...) do { \
+ if (debug) \
+ printk(KERN_DEBUG "random %04d %04d %04d: " \
+ fmt,\
+ input_pool.entropy_count,\
+ blocking_pool.entropy_count,\
+ nonblocking_pool.entropy_count,\
+ ## arg); } while (0)
#else
#define DEBUG_ENT(fmt, arg...) do {} while (0)
#endif
@@ -394,7 +396,7 @@ module_param(debug, bool, 0644);
struct entropy_store;
struct entropy_store {
- /* mostly-read data: */
+ /* read-only data: */
struct poolinfo *poolinfo;
__u32 *pool;
const char *name;
@@ -402,7 +404,7 @@ struct entropy_store {
struct entropy_store *pull;
/* read-write data: */
- spinlock_t lock ____cacheline_aligned_in_smp;
+ spinlock_t lock;
unsigned add_ptr;
int entropy_count;
int input_rotate;
@@ -438,25 +440,26 @@ static struct entropy_store nonblocking_pool = {
};
/*
- * This function adds a byte into the entropy "pool". It does not
+ * This function adds bytes into the entropy "pool". It does not
* update the entropy estimate. The caller should call
- * credit_entropy_store if this is appropriate.
+ * credit_entropy_bits if this is appropriate.
*
* The pool is stirred with a primitive polynomial of the appropriate
* degree, and then twisted. We twist by three bits at a time because
* it's cheap to do so and helps slightly in the expected case where
* the entropy is concentrated in the low-order bits.
*/
-static void __add_entropy_words(struct entropy_store *r, const __u32 *in,
- int nwords, __u32 out[16])
+static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
+ int nbytes, __u8 out[64])
{
static __u32 const twist_table[8] = {
0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
- unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5;
- int new_rotate, input_rotate;
+ unsigned long i, j, tap1, tap2, tap3, tap4, tap5;
+ int input_rotate;
int wordmask = r->poolinfo->poolwords - 1;
- __u32 w, next_w;
+ const char *bytes = in;
+ __u32 w;
unsigned long flags;
/* Taps are constant, so we can load them without holding r->lock. */
@@ -465,78 +468,76 @@ static void __add_entropy_words(struct entropy_store *r, const __u32 *in,
tap3 = r->poolinfo->tap3;
tap4 = r->poolinfo->tap4;
tap5 = r->poolinfo->tap5;
- next_w = *in++;
spin_lock_irqsave(&r->lock, flags);
- prefetch_range(r->pool, wordmask);
input_rotate = r->input_rotate;
- add_ptr = r->add_ptr;
+ i = r->add_ptr;
- while (nwords--) {
- w = rol32(next_w, input_rotate);
- if (nwords > 0)
- next_w = *in++;
- i = add_ptr = (add_ptr - 1) & wordmask;
- /*
- * Normally, we add 7 bits of rotation to the pool.
- * At the beginning of the pool, add an extra 7 bits
- * rotation, so that successive passes spread the
- * input bits across the pool evenly.
- */
- new_rotate = input_rotate + 14;
- if (i)
- new_rotate = input_rotate + 7;
- input_rotate = new_rotate & 31;
+ /* mix one byte at a time to simplify size handling and churn faster */
+ while (nbytes--) {
+ w = rol32(*bytes++, input_rotate & 31);
+ i = (i - 1) & wordmask;
/* XOR in the various taps */
+ w ^= r->pool[i];
w ^= r->pool[(i + tap1) & wordmask];
w ^= r->pool[(i + tap2) & wordmask];
w ^= r->pool[(i + tap3) & wordmask];
w ^= r->pool[(i + tap4) & wordmask];
w ^= r->pool[(i + tap5) & wordmask];
- w ^= r->pool[i];
+
+ /* Mix the result back in with a twist */
r->pool[i] = (w >> 3) ^ twist_table[w & 7];
+
+ /*
+ * Normally, we add 7 bits of rotation to the pool.
+ * At the beginning of the pool, add an extra 7 bits
+ * rotation, so that successive passes spread the
+ * input bits across the pool evenly.
+ */
+ input_rotate += i ? 7 : 14;
}
r->input_rotate = input_rotate;
- r->add_ptr = add_ptr;
+ r->add_ptr = i;
- if (out) {
- for (i = 0; i < 16; i++) {
- out[i] = r->pool[add_ptr];
- add_ptr = (add_ptr - 1) & wordmask;
- }
- }
+ if (out)
+ for (j = 0; j < 16; j++)
+ ((__u32 *)out)[j] = r->pool[(i - j) & wordmask];
spin_unlock_irqrestore(&r->lock, flags);
}
-static inline void add_entropy_words(struct entropy_store *r, const __u32 *in,
- int nwords)
+static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
{
- __add_entropy_words(r, in, nwords, NULL);
+ mix_pool_bytes_extract(r, in, bytes, NULL);
}
/*
* Credit (or debit) the entropy store with n bits of entropy
*/
-static void credit_entropy_store(struct entropy_store *r, int nbits)
+static void credit_entropy_bits(struct entropy_store *r, int nbits)
{
unsigned long flags;
+ if (!nbits)
+ return;
+
spin_lock_irqsave(&r->lock, flags);
- if (r->entropy_count + nbits < 0) {
- DEBUG_ENT("negative entropy/overflow (%d+%d)\n",
- r->entropy_count, nbits);
+ DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);
+ r->entropy_count += nbits;
+ if (r->entropy_count < 0) {
+ DEBUG_ENT("negative entropy/overflow\n");
r->entropy_count = 0;
- } else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) {
+ } else if (r->entropy_count > r->poolinfo->POOLBITS)
r->entropy_count = r->poolinfo->POOLBITS;
- } else {
- r->entropy_count += nbits;
- if (nbits)
- DEBUG_ENT("added %d entropy credits to %s\n",
- nbits, r->name);
+
+ /* should we wake readers? */
+ if (r == &input_pool &&
+ r->entropy_count >= random_read_wakeup_thresh) {
+ wake_up_interruptible(&random_read_wait);
+ kill_fasync(&fasync, SIGIO, POLL_IN);
}
spin_unlock_irqrestore(&r->lock, flags);
@@ -551,7 +552,7 @@ static void credit_entropy_store(struct entropy_store *r, int nbits)
/* There is one of these per entropy source */
struct timer_rand_state {
cycles_t last_time;
- long last_delta,last_delta2;
+ long last_delta, last_delta2;
unsigned dont_count_entropy:1;
};
@@ -586,7 +587,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
sample.jiffies = jiffies;
sample.cycles = get_cycles();
sample.num = num;
- add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4);
+ mix_pool_bytes(&input_pool, &sample, sizeof(sample));
/*
* Calculate number of bits of randomness we probably added.
@@ -620,13 +621,9 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
* Round down by 1 bit on general principles,
* and limit entropy entimate to 12 bits.
*/
- credit_entropy_store(&input_pool,
- min_t(int, fls(delta>>1), 11));
+ credit_entropy_bits(&input_pool,
+ min_t(int, fls(delta>>1), 11));
}
-
- if(input_pool.entropy_count >= random_read_wakeup_thresh)
- wake_up_interruptible(&random_read_wait);
-
out:
preempt_enable();
}
@@ -677,7 +674,7 @@ void add_disk_randomness(struct gendisk *disk)
*
*********************************************************************/
-static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+static ssize_t extract_entropy(struct entropy_store *r, void *buf,
size_t nbytes, int min, int rsvd);
/*
@@ -704,10 +701,10 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
"(%d of %d requested)\n",
r->name, bytes * 8, nbytes * 8, r->entropy_count);
- bytes=extract_entropy(r->pull, tmp, bytes,
- random_read_wakeup_thresh / 8, rsvd);
- add_entropy_words(r, tmp, (bytes + 3) / 4);
- credit_entropy_store(r, bytes*8);
+ bytes = extract_entropy(r->pull, tmp, bytes,
+ random_read_wakeup_thresh / 8, rsvd);
+ mix_pool_bytes(r, tmp, bytes);
+ credit_entropy_bits(r, bytes*8);
}
}
@@ -744,13 +741,15 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
if (r->limit && nbytes + reserved >= r->entropy_count / 8)
nbytes = r->entropy_count/8 - reserved;
- if(r->entropy_count / 8 >= nbytes + reserved)
+ if (r->entropy_count / 8 >= nbytes + reserved)
r->entropy_count -= nbytes*8;
else
r->entropy_count = reserved;
- if (r->entropy_count < random_write_wakeup_thresh)
+ if (r->entropy_count < random_write_wakeup_thresh) {
wake_up_interruptible(&random_write_wait);
+ kill_fasync(&fasync, SIGIO, POLL_OUT);
+ }
}
DEBUG_ENT("debiting %d entropy credits from %s%s\n",
@@ -764,45 +763,46 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
static void extract_buf(struct entropy_store *r, __u8 *out)
{
int i;
- __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS];
+ __u32 hash[5], workspace[SHA_WORKSPACE_WORDS];
+ __u8 extract[64];
+
+ /* Generate a hash across the pool, 16 words (512 bits) at a time */
+ sha_init(hash);
+ for (i = 0; i < r->poolinfo->poolwords; i += 16)
+ sha_transform(hash, (__u8 *)(r->pool + i), workspace);
- sha_init(buf);
/*
- * As we hash the pool, we mix intermediate values of
- * the hash back into the pool. This eliminates
- * backtracking attacks (where the attacker knows
- * the state of the pool plus the current outputs, and
- * attempts to find previous ouputs), unless the hash
- * function can be inverted.
+ * We mix the hash back into the pool to prevent backtracking
+ * attacks (where the attacker knows the state of the pool
+ * plus the current outputs, and attempts to find previous
+ * ouputs), unless the hash function can be inverted. By
+ * mixing at least a SHA1 worth of hash data back, we make
+ * brute-forcing the feedback as hard as brute-forcing the
+ * hash.
*/
- for (i = 0; i < r->poolinfo->poolwords; i += 16) {
- /* hash blocks of 16 words = 512 bits */
- sha_transform(buf, (__u8 *)(r->pool + i), buf + 5);
- /* feed back portion of the resulting hash */
- add_entropy_words(r, &buf[i % 5], 1);
- }
+ mix_pool_bytes_extract(r, hash, sizeof(hash), extract);
/*
- * To avoid duplicates, we atomically extract a
- * portion of the pool while mixing, and hash one
- * final time.
+ * To avoid duplicates, we atomically extract a portion of the
+ * pool while mixing, and hash one final time.
*/
- __add_entropy_words(r, &buf[i % 5], 1, data);
- sha_transform(buf, (__u8 *)data, buf + 5);
+ sha_transform(hash, extract, workspace);
+ memset(extract, 0, sizeof(extract));
+ memset(workspace, 0, sizeof(workspace));
/*
- * In case the hash function has some recognizable
- * output pattern, we fold it in half.
+ * In case the hash function has some recognizable output
+ * pattern, we fold it in half. Thus, we always feed back
+ * twice as much data as we output.
*/
-
- buf[0] ^= buf[3];
- buf[1] ^= buf[4];
- buf[2] ^= rol32(buf[2], 16);
- memcpy(out, buf, EXTRACT_SIZE);
- memset(buf, 0, sizeof(buf));
+ hash[0] ^= hash[3];
+ hash[1] ^= hash[4];
+ hash[2] ^= rol32(hash[2], 16);
+ memcpy(out, hash, EXTRACT_SIZE);
+ memset(hash, 0, sizeof(hash));
}
-static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+static ssize_t extract_entropy(struct entropy_store *r, void *buf,
size_t nbytes, int min, int reserved)
{
ssize_t ret = 0, i;
@@ -872,7 +872,6 @@ void get_random_bytes(void *buf, int nbytes)
{
extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
}
-
EXPORT_SYMBOL(get_random_bytes);
/*
@@ -894,12 +893,11 @@ static void init_std_data(struct entropy_store *r)
spin_unlock_irqrestore(&r->lock, flags);
now = ktime_get_real();
- add_entropy_words(r, (__u32 *)&now, sizeof(now)/4);
- add_entropy_words(r, (__u32 *)utsname(),
- sizeof(*(utsname()))/4);
+ mix_pool_bytes(r, &now, sizeof(now));
+ mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
}
-static int __init rand_initialize(void)
+static int rand_initialize(void)
{
init_std_data(&input_pool);
init_std_data(&blocking_pool);
@@ -940,7 +938,7 @@ void rand_initialize_disk(struct gendisk *disk)
#endif
static ssize_t
-random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
+random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
ssize_t n, retval = 0, count = 0;
@@ -1002,8 +1000,7 @@ random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
}
static ssize_t
-urandom_read(struct file * file, char __user * buf,
- size_t nbytes, loff_t *ppos)
+urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
return extract_entropy_user(&nonblocking_pool, buf, nbytes);
}
@@ -1038,16 +1035,15 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
count -= bytes;
p += bytes;
- add_entropy_words(r, buf, (bytes + 3) / 4);
+ mix_pool_bytes(r, buf, bytes);
cond_resched();
}
return 0;
}
-static ssize_t
-random_write(struct file * file, const char __user * buffer,
- size_t count, loff_t *ppos)
+static ssize_t random_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
size_t ret;
struct inode *inode = file->f_path.dentry->d_inode;
@@ -1064,9 +1060,7 @@ random_write(struct file * file, const char __user * buffer,
return (ssize_t)count;
}
-static int
-random_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
+static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
int size, ent_count;
int __user *p = (int __user *)arg;
@@ -1074,8 +1068,8 @@ random_ioctl(struct inode * inode, struct file * file,
switch (cmd) {
case RNDGETENTCNT:
- ent_count = input_pool.entropy_count;
- if (put_user(ent_count, p))
+ /* inherently racy, no point locking */
+ if (put_user(input_pool.entropy_count, p))
return -EFAULT;
return 0;
case RNDADDTOENTCNT:
@@ -1083,13 +1077,7 @@ random_ioctl(struct inode * inode, struct file * file,
return -EPERM;
if (get_user(ent_count, p))
return -EFAULT;
- credit_entropy_store(&input_pool, ent_count);
- /*
- * Wake up waiting processes if we have enough
- * entropy.
- */
- if (input_pool.entropy_count >= random_read_wakeup_thresh)
- wake_up_interruptible(&random_read_wait);
+ credit_entropy_bits(&input_pool, ent_count);
return 0;
case RNDADDENTROPY:
if (!capable(CAP_SYS_ADMIN))
@@ -1104,39 +1092,45 @@ random_ioctl(struct inode * inode, struct file * file,
size);
if (retval < 0)
return retval;
- credit_entropy_store(&input_pool, ent_count);
- /*
- * Wake up waiting processes if we have enough
- * entropy.
- */
- if (input_pool.entropy_count >= random_read_wakeup_thresh)
- wake_up_interruptible(&random_read_wait);
+ credit_entropy_bits(&input_pool, ent_count);
return 0;
case RNDZAPENTCNT:
case RNDCLEARPOOL:
/* Clear the entropy pool counters. */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- init_std_data(&input_pool);
- init_std_data(&blocking_pool);
- init_std_data(&nonblocking_pool);
+ rand_initialize();
return 0;
default:
return -EINVAL;
}
}
+static int random_fasync(int fd, struct file *filp, int on)
+{
+ return fasync_helper(fd, filp, on, &fasync);
+}
+
+static int random_release(struct inode *inode, struct file *filp)
+{
+ return fasync_helper(-1, filp, 0, &fasync);
+}
+
const struct file_operations random_fops = {
.read = random_read,
.write = random_write,
.poll = random_poll,
- .ioctl = random_ioctl,
+ .unlocked_ioctl = random_ioctl,
+ .fasync = random_fasync,
+ .release = random_release,
};
const struct file_operations urandom_fops = {
.read = urandom_read,
.write = random_write,
- .ioctl = random_ioctl,
+ .unlocked_ioctl = random_ioctl,
+ .fasync = random_fasync,
+ .release = random_release,
};
/***************************************************************
@@ -1157,7 +1151,6 @@ void generate_random_uuid(unsigned char uuid_out[16])
/* Set the UUID variant to DCE */
uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;
}
-
EXPORT_SYMBOL(generate_random_uuid);
/********************************************************************
@@ -1339,7 +1332,7 @@ ctl_table random_table[] = {
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
+static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12])
{
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
@@ -1487,8 +1480,8 @@ __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
*/
memcpy(hash, saddr, 16);
- hash[4]=((__force u16)sport << 16) + (__force u16)dport;
- memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
+ hash[4] = ((__force u16)sport << 16) + (__force u16)dport;
+ memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
seq += keyptr->count;
@@ -1538,10 +1531,10 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
* Note that the words are placed into the starting vector, which is
* then mixed with a partial MD4 over random data.
*/
- hash[0]=(__force u32)saddr;
- hash[1]=(__force u32)daddr;
- hash[2]=((__force u16)sport << 16) + (__force u16)dport;
- hash[3]=keyptr->secret[11];
+ hash[0] = (__force u32)saddr;
+ hash[1] = (__force u32)daddr;
+ hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+ hash[3] = keyptr->secret[11];
seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
seq += keyptr->count;
@@ -1556,10 +1549,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
* Choosing a clock of 64 ns period is OK. (period of 274 s)
*/
seq += ktime_to_ns(ktime_get_real()) >> 6;
-#if 0
- printk("init_seq(%lx, %lx, %d, %d) = %d\n",
- saddr, daddr, sport, dport, seq);
-#endif
+
return seq;
}
@@ -1582,14 +1572,15 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport)
+u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+ __be16 dport)
{
struct keydata *keyptr = get_keyptr();
u32 hash[12];
memcpy(hash, saddr, 16);
hash[4] = (__force u32)dport;
- memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
+ memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
return twothirdsMD4Transform((const __u32 *)daddr, hash);
}
@@ -1617,13 +1608,9 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
seq += ktime_to_ns(ktime_get_real());
seq &= (1ull << 48) - 1;
-#if 0
- printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
- saddr, daddr, sport, dport, seq);
-#endif
+
return seq;
}
-
EXPORT_SYMBOL(secure_dccp_sequence_number);
#endif
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
index f4f837f86829..a03a538a3efb 100644
--- a/drivers/char/rio/cirrus.h
+++ b/drivers/char/rio/cirrus.h
@@ -43,83 +43,83 @@
/* Bit fields for particular registers shared with driver */
/* COR1 - driver and RTA */
-#define COR1_ODD 0x80 /* Odd parity */
-#define COR1_EVEN 0x00 /* Even parity */
-#define COR1_NOP 0x00 /* No parity */
-#define COR1_FORCE 0x20 /* Force parity */
-#define COR1_NORMAL 0x40 /* With parity */
-#define COR1_1STOP 0x00 /* 1 stop bit */
-#define COR1_15STOP 0x04 /* 1.5 stop bits */
-#define COR1_2STOP 0x08 /* 2 stop bits */
-#define COR1_5BITS 0x00 /* 5 data bits */
-#define COR1_6BITS 0x01 /* 6 data bits */
-#define COR1_7BITS 0x02 /* 7 data bits */
-#define COR1_8BITS 0x03 /* 8 data bits */
-
-#define COR1_HOST 0xef /* Safe host bits */
+#define RIOC_COR1_ODD 0x80 /* Odd parity */
+#define RIOC_COR1_EVEN 0x00 /* Even parity */
+#define RIOC_COR1_NOP 0x00 /* No parity */
+#define RIOC_COR1_FORCE 0x20 /* Force parity */
+#define RIOC_COR1_NORMAL 0x40 /* With parity */
+#define RIOC_COR1_1STOP 0x00 /* 1 stop bit */
+#define RIOC_COR1_15STOP 0x04 /* 1.5 stop bits */
+#define RIOC_COR1_2STOP 0x08 /* 2 stop bits */
+#define RIOC_COR1_5BITS 0x00 /* 5 data bits */
+#define RIOC_COR1_6BITS 0x01 /* 6 data bits */
+#define RIOC_COR1_7BITS 0x02 /* 7 data bits */
+#define RIOC_COR1_8BITS 0x03 /* 8 data bits */
+
+#define RIOC_COR1_HOST 0xef /* Safe host bits */
/* RTA only */
-#define COR1_CINPCK 0x00 /* Check parity of received characters */
-#define COR1_CNINPCK 0x10 /* Don't check parity */
+#define RIOC_COR1_CINPCK 0x00 /* Check parity of received characters */
+#define RIOC_COR1_CNINPCK 0x10 /* Don't check parity */
/* COR2 bits for both RTA and driver use */
-#define COR2_IXANY 0x80 /* IXANY - any character is XON */
-#define COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
-#define COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
+#define RIOC_COR2_IXANY 0x80 /* IXANY - any character is XON */
+#define RIOC_COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
+#define RIOC_COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
/* Additional driver bits */
-#define COR2_HUPCL 0x20 /* Hang up on close */
-#define COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
-#define COR2_IXOFF 0x01 /* Enable rx software flow control */
-#define COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
+#define RIOC_COR2_HUPCL 0x20 /* Hang up on close */
+#define RIOC_COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
+#define RIOC_COR2_IXOFF 0x01 /* Enable rx software flow control */
+#define RIOC_COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
/* RTA use only */
-#define COR2_ETC 0x20 /* Embedded transmit options */
-#define COR2_LOCAL 0x10 /* Local loopback mode */
-#define COR2_REMOTE 0x08 /* Remote loopback mode */
-#define COR2_HOST 0xc2 /* Safe host bits */
+#define RIOC_COR2_ETC 0x20 /* Embedded transmit options */
+#define RIOC_COR2_LOCAL 0x10 /* Local loopback mode */
+#define RIOC_COR2_REMOTE 0x08 /* Remote loopback mode */
+#define RIOC_COR2_HOST 0xc2 /* Safe host bits */
/* COR3 - RTA use only */
-#define COR3_SCDRNG 0x80 /* Enable special char detect for range */
-#define COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
-#define COR3_FCT 0x20 /* Flow control transparency */
-#define COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
-#define COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
-#define COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
-#define COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
-#define COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
-
-#define COR3_THRESHOLD COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
-
-#define COR3_DEFAULT (COR3_FCT | COR3_THRESHOLD)
+#define RIOC_COR3_SCDRNG 0x80 /* Enable special char detect for range */
+#define RIOC_COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
+#define RIOC_COR3_FCT 0x20 /* Flow control transparency */
+#define RIOC_COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
+#define RIOC_COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
+
+#define RIOC_COR3_THRESHOLD RIOC_COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
+
+#define RIOC_COR3_DEFAULT (RIOC_COR3_FCT | RIOC_COR3_THRESHOLD)
/* Default bits for COR3 */
/* COR4 driver and RTA use */
-#define COR4_IGNCR 0x80 /* Throw away CR's on input */
-#define COR4_ICRNL 0x40 /* Map CR -> NL on input */
-#define COR4_INLCR 0x20 /* Map NL -> CR on input */
-#define COR4_IGNBRK 0x10 /* Ignore Break */
-#define COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
-#define COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
+#define RIOC_COR4_IGNCR 0x80 /* Throw away CR's on input */
+#define RIOC_COR4_ICRNL 0x40 /* Map CR -> NL on input */
+#define RIOC_COR4_INLCR 0x20 /* Map NL -> CR on input */
+#define RIOC_COR4_IGNBRK 0x10 /* Ignore Break */
+#define RIOC_COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
+#define RIOC_COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
/* COR4 driver only */
-#define COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
-#define COR4_PARMRK 0x02 /* PARMRK */
+#define RIOC_COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
+#define RIOC_COR4_PARMRK 0x02 /* PARMRK */
-#define COR4_HOST 0xf8 /* Safe host bits */
+#define RIOC_COR4_HOST 0xf8 /* Safe host bits */
/* COR4 RTA only */
-#define COR4_CIGNPAR 0x02 /* Thrown away bad characters */
-#define COR4_CPARMRK 0x04 /* PARMRK characters */
-#define COR4_CNPARMRK 0x03 /* Don't PARMRK */
+#define RIOC_COR4_CIGNPAR 0x02 /* Thrown away bad characters */
+#define RIOC_COR4_CPARMRK 0x04 /* PARMRK characters */
+#define RIOC_COR4_CNPARMRK 0x03 /* Don't PARMRK */
/* COR5 driver and RTA use */
-#define COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
-#define COR5_LNE 0x40 /* Enable LNEXT processing */
-#define COR5_CMOE 0x20 /* Match good and errored characters */
-#define COR5_ONLCR 0x02 /* NL -> CR NL on output */
-#define COR5_OCRNL 0x01 /* CR -> NL on output */
+#define RIOC_COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
+#define RIOC_COR5_LNE 0x40 /* Enable LNEXT processing */
+#define RIOC_COR5_CMOE 0x20 /* Match good and errored characters */
+#define RIOC_COR5_ONLCR 0x02 /* NL -> CR NL on output */
+#define RIOC_COR5_OCRNL 0x01 /* CR -> NL on output */
/*
** Spare bits - these are not used in the CIRRUS registers, so we use
@@ -128,86 +128,86 @@
/*
** tstop and tbusy indication
*/
-#define COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
-#define COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
/*
** TAB3
*/
-#define COR5_TAB3 0x10 /* TAB3 mode */
+#define RIOC_COR5_TAB3 0x10 /* TAB3 mode */
-#define COR5_HOST 0xc3 /* Safe host bits */
+#define RIOC_COR5_HOST 0xc3 /* Safe host bits */
/* CCSR */
-#define CCSR_TXFLOFF 0x04 /* Tx is xoffed */
+#define RIOC_CCSR_TXFLOFF 0x04 /* Tx is xoffed */
/* MSVR1 */
/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
serial option.
*/
-#define MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
-#define MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
-#define MSVR1_RI 0x20 /* RI */
-#define MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
-#define MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
+#define RIOC_MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
+#define RIOC_MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
+#define RIOC_MSVR1_RI 0x20 /* RI */
+#define RIOC_MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
+#define RIOC_MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
/* Next two used to indicate state of tbusy and tstop to driver */
-#define MSVR1_TSTOP 0x08 /* Set if port flow controlled */
-#define MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
+#define RIOC_MSVR1_TSTOP 0x08 /* Set if port flow controlled */
+#define RIOC_MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
-#define MSVR1_HOST 0xf3 /* The bits the host wants */
+#define RIOC_MSVR1_HOST 0xf3 /* The bits the host wants */
/* Defines for the subscripts of a CONFIG packet */
-#define CONFIG_COR1 1 /* Option register 1 */
-#define CONFIG_COR2 2 /* Option register 2 */
-#define CONFIG_COR4 3 /* Option register 4 */
-#define CONFIG_COR5 4 /* Option register 5 */
-#define CONFIG_TXXON 5 /* Tx XON character */
-#define CONFIG_TXXOFF 6 /* Tx XOFF character */
-#define CONFIG_RXXON 7 /* Rx XON character */
-#define CONFIG_RXXOFF 8 /* Rx XOFF character */
-#define CONFIG_LNEXT 9 /* LNEXT character */
-#define CONFIG_TXBAUD 10 /* Tx baud rate */
-#define CONFIG_RXBAUD 11 /* Rx baud rate */
-
-#define PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
+#define RIOC_CONFIG_COR1 1 /* Option register 1 */
+#define RIOC_CONFIG_COR2 2 /* Option register 2 */
+#define RIOC_CONFIG_COR4 3 /* Option register 4 */
+#define RIOC_CONFIG_COR5 4 /* Option register 5 */
+#define RIOC_CONFIG_TXXON 5 /* Tx XON character */
+#define RIOC_CONFIG_TXXOFF 6 /* Tx XOFF character */
+#define RIOC_CONFIG_RXXON 7 /* Rx XON character */
+#define RIOC_CONFIG_RXXOFF 8 /* Rx XOFF character */
+#define RIOC_CONFIG_LNEXT 9 /* LNEXT character */
+#define RIOC_CONFIG_TXBAUD 10 /* Tx baud rate */
+#define RIOC_CONFIG_RXBAUD 11 /* Rx baud rate */
+
+#define RIOC_PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
be used
*/
-#define OPEN 0x00 /* Open a port */
-#define CONFIG 0x01 /* Configure a port */
-#define MOPEN 0x02 /* Modem open (block for DCD) */
-#define CLOSE 0x03 /* Close a port */
-#define WFLUSH (0x04 | PRE_EMPTIVE) /* Write flush */
-#define RFLUSH (0x05 | PRE_EMPTIVE) /* Read flush */
-#define RESUME (0x06 | PRE_EMPTIVE) /* Resume if xoffed */
-#define SBREAK 0x07 /* Start break */
-#define EBREAK 0x08 /* End break */
-#define SUSPEND (0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
-#define FCLOSE (0x0a | PRE_EMPTIVE) /* Force close */
-#define XPRINT 0x0b /* Xprint packet */
-#define MBIS (0x0c | PRE_EMPTIVE) /* Set modem lines */
-#define MBIC (0x0d | PRE_EMPTIVE) /* Clear modem lines */
-#define MSET (0x0e | PRE_EMPTIVE) /* Set modem lines */
-#define PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
-#define MGET (0x10 | PRE_EMPTIVE) /* Force update of modem status */
-#define MEMDUMP (0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */
-#define READ_REGISTER (0x12 | PRE_EMPTIVE) /* Read CD1400 register (debug) */
+#define RIOC_OPEN 0x00 /* Open a port */
+#define RIOC_CONFIG 0x01 /* Configure a port */
+#define RIOC_MOPEN 0x02 /* Modem open (block for DCD) */
+#define RIOC_CLOSE 0x03 /* Close a port */
+#define RIOC_WFLUSH (0x04 | RIOC_PRE_EMPTIVE) /* Write flush */
+#define RIOC_RFLUSH (0x05 | RIOC_PRE_EMPTIVE) /* Read flush */
+#define RIOC_RESUME (0x06 | RIOC_PRE_EMPTIVE) /* Resume if xoffed */
+#define RIOC_SBREAK 0x07 /* Start break */
+#define RIOC_EBREAK 0x08 /* End break */
+#define RIOC_SUSPEND (0x09 | RIOC_PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
+#define RIOC_FCLOSE (0x0a | RIOC_PRE_EMPTIVE) /* Force close */
+#define RIOC_XPRINT 0x0b /* Xprint packet */
+#define RIOC_MBIS (0x0c | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_MBIC (0x0d | RIOC_PRE_EMPTIVE) /* Clear modem lines */
+#define RIOC_MSET (0x0e | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
+#define RIOC_MGET (0x10 | RIOC_PRE_EMPTIVE) /* Force update of modem status */
+#define RIOC_MEMDUMP (0x11 | RIOC_PRE_EMPTIVE) /* Send back mem from addr supplied */
+#define RIOC_READ_REGISTER (0x12 | RIOC_PRE_EMPTIVE) /* Read CD1400 register (debug) */
/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
use data[4] / data[3] to indicate current state and modem status respectively
*/
-#define COMPLETE (0x20 | PRE_EMPTIVE)
+#define RIOC_COMPLETE (0x20 | RIOC_PRE_EMPTIVE)
/* Command complete */
-#define BREAK_RECEIVED (0x21 | PRE_EMPTIVE)
+#define RIOC_BREAK_RECEIVED (0x21 | RIOC_PRE_EMPTIVE)
/* Break received */
-#define MODEM_STATUS (0x22 | PRE_EMPTIVE)
+#define RIOC_MODEM_STATUS (0x22 | RIOC_PRE_EMPTIVE)
/* Change in modem status */
/* "Command" packet that could go either way - handshake wake-up */
-#define HANDSHAKE (0x23 | PRE_EMPTIVE)
+#define RIOC_HANDSHAKE (0x23 | RIOC_PRE_EMPTIVE)
/* Wake-up to HOST / RTA */
#endif
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 0ce96670f979..412777cd1e68 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -344,7 +344,7 @@ int rio_minor(struct tty_struct *tty)
static int rio_set_real_termios(void *ptr)
{
- return RIOParam((struct Port *) ptr, CONFIG, 1, 1);
+ return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1);
}
@@ -487,7 +487,7 @@ static int rio_get_CD(void *ptr)
int rv;
func_enter();
- rv = (PortP->ModemState & MSVR1_CD) != 0;
+ rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0;
rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
@@ -607,7 +607,8 @@ static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd
rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
rc = -EIO;
} else {
- if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
rc = -EIO;
}
@@ -622,7 +623,8 @@ static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd
l = arg ? arg * 100 : 250;
if (l > 255)
l = 255;
- if (RIOShortCommand(p, PortP, SBREAK, 2, arg ? arg * 100 : 250) == RIO_FAIL) {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2,
+ arg ? arg * 100 : 250) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
rc = -EIO;
}
diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h
index dc3f005614a3..7f26cd7c815e 100644
--- a/drivers/char/rio/rio_linux.h
+++ b/drivers/char/rio/rio_linux.h
@@ -186,9 +186,9 @@ static inline void *rio_memcpy_fromio(void *dest, void __iomem *source, int n)
#ifdef DEBUG
#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0)
-#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __FUNCTION__)
-#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __FUNCTION__)
-#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__FUNCTION__, port->line)
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __func__)
+#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __func__)
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__func__, port->line)
#else
#define rio_dprintk(f, str...) /* nothing */
#define func_enter()
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index bf36959fc121..7b96e0814887 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -417,7 +417,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
PortP = p->RIOPortp[SysPort];
rio_spin_lock_irqsave(&PortP->portSem, flags);
switch (readb(&PktCmdP->Command)) {
- case BREAK_RECEIVED:
+ case RIOC_BREAK_RECEIVED:
rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n");
/* If the current line disc. is not multi-threading and
the current processor is not the default, reset rup_intr
@@ -428,16 +428,16 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
gs_got_break(&PortP->gs);
break;
- case COMPLETE:
+ case RIOC_COMPLETE:
rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts);
subCommand = 1;
switch (readb(&PktCmdP->SubCommand)) {
- case MEMDUMP:
+ case RIOC_MEMDUMP:
rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr));
break;
- case READ_REGISTER:
+ case RIOC_READ_REGISTER:
rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr));
- p->CdRegister = (readb(&PktCmdP->ModemStatus) & MSVR1_HOST);
+ p->CdRegister = (readb(&PktCmdP->ModemStatus) & RIOC_MSVR1_HOST);
break;
default:
subCommand = 0;
@@ -456,14 +456,15 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
rio_dprintk(RIO_DEBUG_CMD, "No change\n");
/* FALLTHROUGH */
- case MODEM_STATUS:
+ case RIOC_MODEM_STATUS:
/*
** Knock out the tbusy and tstop bits, as these are not relevant
** to the check for modem status change (they're just there because
** it's a convenient place to put them!).
*/
ReportedModemStatus = readb(&PktCmdP->ModemStatus);
- if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) {
+ if ((PortP->ModemState & RIOC_MSVR1_HOST) ==
+ (ReportedModemStatus & RIOC_MSVR1_HOST)) {
rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState);
/*
** Update ModemState just in case tbusy or tstop states have
@@ -497,7 +498,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
/*
** Is there a carrier?
*/
- if (PortP->ModemState & MSVR1_CD) {
+ if (PortP->ModemState & RIOC_MSVR1_CD) {
/*
** Has carrier just appeared?
*/
@@ -691,7 +692,7 @@ void RIOPollHostCommands(struct rio_info *p, struct Host *HostP)
*/
rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
FreeMe = RIOCommandRup(p, Rup, HostP, PacketP);
- if (readb(&PacketP->data[5]) == MEMDUMP) {
+ if (readb(&PacketP->data[5]) == RIOC_MEMDUMP) {
rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6])));
rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 32);
}
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index d8eb2bcbe015..d65ceb9a434a 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -422,7 +422,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RIOC_RESUME) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -636,7 +637,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
return -ENXIO;
}
PortP = (p->RIOPortp[PortTty.port]);
- RIOParam(PortP, CONFIG, PortP->State & RIO_MODEM, OK_TO_SLEEP);
+ RIOParam(PortP, RIOC_CONFIG, PortP->State & RIO_MODEM,
+ OK_TO_SLEEP);
return retval;
case RIO_SET_PORT_PARAMS:
@@ -1247,7 +1249,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, PortP, MEMDUMP) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, PortP, RIOC_MEMDUMP) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -1313,7 +1315,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, PortP, RIOC_READ_REGISTER) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -1434,50 +1437,50 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
PktCmdP->PhbNum = port;
switch (Cmd) {
- case MEMDUMP:
+ case RIOC_MEMDUMP:
rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p "
"(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
- PktCmdP->SubCommand = MEMDUMP;
+ PktCmdP->SubCommand = RIOC_MEMDUMP;
PktCmdP->SubAddr = SubCmd.Addr;
break;
- case FCLOSE:
+ case RIOC_FCLOSE:
rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n",
CmdBlkP);
break;
- case READ_REGISTER:
+ case RIOC_READ_REGISTER:
rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) "
"command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
- PktCmdP->SubCommand = READ_REGISTER;
+ PktCmdP->SubCommand = RIOC_READ_REGISTER;
PktCmdP->SubAddr = SubCmd.Addr;
break;
- case RESUME:
+ case RIOC_RESUME:
rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n",
CmdBlkP);
break;
- case RFLUSH:
+ case RIOC_RFLUSH:
rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n",
CmdBlkP);
CmdBlkP->PostFuncP = RIORFlushEnable;
break;
- case SUSPEND:
+ case RIOC_SUSPEND:
rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n",
CmdBlkP);
break;
- case MGET:
+ case RIOC_MGET:
rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n",
CmdBlkP);
break;
- case MSET:
- case MBIC:
- case MBIS:
+ case RIOC_MSET:
+ case RIOC_MBIC:
+ case RIOC_MBIS:
CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command "
"blk %p\n", CmdBlkP);
break;
- case WFLUSH:
+ case RIOC_WFLUSH:
/*
** If we have queued up the maximum number of Write flushes
** allowed then we should not bother sending any more to the
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index 4734e26e1ccd..ea21686c69a4 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -401,9 +401,8 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP)
PortP->InUse = NOT_INUSE;
rio_spin_unlock(&PortP->portSem);
- if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) {
+ if (RIOParam(PortP, RIOC_OPEN, ((PortP->Cor2Copy & (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) == (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL)
continue; /* with next port */
- }
rio_spin_lock(&PortP->portSem);
PortP->MagicFlags &= ~MAGIC_REBOOT;
}
@@ -429,7 +428,7 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP)
*/
PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0];
- writeb(WFLUSH, &PktCmdP->Command);
+ writeb(RIOC_WFLUSH, &PktCmdP->Command);
p = PortP->HostPort % (u16) PORTS_PER_RTA;
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c
index da276ed57b3f..4810b845cc21 100644
--- a/drivers/char/rio/rioparam.c
+++ b/drivers/char/rio/rioparam.c
@@ -177,7 +177,7 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (cmd == OPEN) {
+ if (cmd == RIOC_OPEN) {
/*
** If the port is set to store or lock the parameters, and it is
** paramed with OPEN, we want to restore the saved port termio, but
@@ -241,50 +241,50 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
case CS5:
{
rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n");
- Cor1 |= COR1_5BITS;
+ Cor1 |= RIOC_COR1_5BITS;
break;
}
case CS6:
{
rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n");
- Cor1 |= COR1_6BITS;
+ Cor1 |= RIOC_COR1_6BITS;
break;
}
case CS7:
{
rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n");
- Cor1 |= COR1_7BITS;
+ Cor1 |= RIOC_COR1_7BITS;
break;
}
case CS8:
{
rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n");
- Cor1 |= COR1_8BITS;
+ Cor1 |= RIOC_COR1_8BITS;
break;
}
}
if (TtyP->termios->c_cflag & CSTOPB) {
rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n");
- Cor1 |= COR1_2STOP;
+ Cor1 |= RIOC_COR1_2STOP;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n");
- Cor1 |= COR1_1STOP;
+ Cor1 |= RIOC_COR1_1STOP;
}
if (TtyP->termios->c_cflag & PARENB) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n");
- Cor1 |= COR1_NORMAL;
+ Cor1 |= RIOC_COR1_NORMAL;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n");
- Cor1 |= COR1_NOP;
+ Cor1 |= RIOC_COR1_NOP;
}
if (TtyP->termios->c_cflag & PARODD) {
rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n");
- Cor1 |= COR1_ODD;
+ Cor1 |= RIOC_COR1_ODD;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n");
- Cor1 |= COR1_EVEN;
+ Cor1 |= RIOC_COR1_EVEN;
}
/*
@@ -292,11 +292,11 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
*/
if (TtyP->termios->c_iflag & IXON) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n");
- Cor2 |= COR2_IXON;
+ Cor2 |= RIOC_COR2_IXON;
} else {
if (PortP->Config & RIO_IXON) {
rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n");
- Cor2 |= COR2_IXON;
+ Cor2 |= RIOC_COR2_IXON;
} else
rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n");
}
@@ -304,29 +304,29 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
if (TtyP->termios->c_iflag & IXANY) {
if (PortP->Config & RIO_IXANY) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n");
- Cor2 |= COR2_IXANY;
+ Cor2 |= RIOC_COR2_IXANY;
} else
rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n");
}
if (TtyP->termios->c_iflag & IXOFF) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n");
- Cor2 |= COR2_IXOFF;
+ Cor2 |= RIOC_COR2_IXOFF;
}
if (TtyP->termios->c_cflag & HUPCL) {
rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n");
- Cor2 |= COR2_HUPCL;
+ Cor2 |= RIOC_COR2_HUPCL;
}
if (C_CRTSCTS(TtyP)) {
rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n");
- Cor2 |= COR2_CTSFLOW;
- Cor2 |= COR2_RTSFLOW;
+ Cor2 |= RIOC_COR2_CTSFLOW;
+ Cor2 |= RIOC_COR2_RTSFLOW;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n");
- Cor2 &= ~COR2_CTSFLOW;
- Cor2 &= ~COR2_RTSFLOW;
+ Cor2 &= ~RIOC_COR2_CTSFLOW;
+ Cor2 &= ~RIOC_COR2_RTSFLOW;
}
@@ -341,36 +341,36 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
*/
if (TtyP->termios->c_iflag & IGNBRK) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n");
- Cor4 |= COR4_IGNBRK;
+ Cor4 |= RIOC_COR4_IGNBRK;
}
if (!(TtyP->termios->c_iflag & BRKINT)) {
rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n");
- Cor4 |= COR4_NBRKINT;
+ Cor4 |= RIOC_COR4_NBRKINT;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on break condition\n");
}
if (TtyP->termios->c_iflag & INLCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n");
- Cor4 |= COR4_INLCR;
+ Cor4 |= RIOC_COR4_INLCR;
}
if (TtyP->termios->c_iflag & IGNCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n");
- Cor4 |= COR4_IGNCR;
+ Cor4 |= RIOC_COR4_IGNCR;
}
if (TtyP->termios->c_iflag & ICRNL) {
rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n");
- Cor4 |= COR4_ICRNL;
+ Cor4 |= RIOC_COR4_ICRNL;
}
if (TtyP->termios->c_iflag & IGNPAR) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n");
- Cor4 |= COR4_IGNPAR;
+ Cor4 |= RIOC_COR4_IGNPAR;
}
if (TtyP->termios->c_iflag & PARMRK) {
rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n");
- Cor4 |= COR4_PARMRK;
+ Cor4 |= RIOC_COR4_PARMRK;
}
/*
@@ -378,22 +378,22 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
** on reception of a config packet.
** The download code handles the zero baud condition.
*/
- Cor4 |= COR4_RAISEMOD;
+ Cor4 |= RIOC_COR4_RAISEMOD;
/*
** COR 5
*/
- Cor5 = COR5_CMOE;
+ Cor5 = RIOC_COR5_CMOE;
/*
** Set to monitor tbusy/tstop (or not).
*/
if (PortP->MonitorTstate)
- Cor5 |= COR5_TSTATE_ON;
+ Cor5 |= RIOC_COR5_TSTATE_ON;
else
- Cor5 |= COR5_TSTATE_OFF;
+ Cor5 |= RIOC_COR5_TSTATE_OFF;
/*
** Could set LNE here if you wanted LNext processing. SVR4 will use it.
@@ -401,24 +401,24 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
if (TtyP->termios->c_iflag & ISTRIP) {
rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n");
if (!(PortP->State & RIO_TRIAD_MODE)) {
- Cor5 |= COR5_ISTRIP;
+ Cor5 |= RIOC_COR5_ISTRIP;
}
}
if (TtyP->termios->c_oflag & ONLCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_ONLCR;
+ Cor5 |= RIOC_COR5_ONLCR;
}
if (TtyP->termios->c_oflag & OCRNL) {
rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_OCRNL;
+ Cor5 |= RIOC_COR5_OCRNL;
}
if ((TtyP->termios->c_oflag & TABDLY) == TAB3) {
rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_TAB3;
+ Cor5 |= RIOC_COR5_TAB3;
}
/*
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index 1cb8580a161d..c99354843be1 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -211,7 +211,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n");
if (repeat_this-- <= 0) {
rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
retval = -EINTR;
goto bombout;
}
@@ -264,7 +264,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
here. If I read the docs correctly the "open"
command piggybacks the parameters immediately.
-- REW */
- RIOParam(PortP, OPEN, 1, OK_TO_SLEEP); /* Open the port */
+ RIOParam(PortP, RIOC_OPEN, 1, OK_TO_SLEEP); /* Open the port */
rio_spin_lock_irqsave(&PortP->portSem, flags);
/*
@@ -275,7 +275,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
func_exit();
return -EINTR;
}
@@ -297,7 +297,8 @@ int riotopen(struct tty_struct *tty, struct file *filp)
** insert test for carrier here. -- ???
** I already see that test here. What's the deal? -- REW
*/
- if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) {
+ if ((PortP->gs.tty->termios->c_cflag & CLOCAL) ||
+ (PortP->ModemState & RIOC_MSVR1_CD)) {
rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort);
/*
tp->tm.c_state |= CARR_ON;
@@ -325,7 +326,7 @@ int riotopen(struct tty_struct *tty, struct file *filp)
** I think it's OK. -- REW
*/
rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort);
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
/*
tp->tm.c_state &= ~WOPEN;
*/
@@ -416,7 +417,7 @@ int riotclose(void *ptr)
*/
PortP->State &= ~RIO_MOPEN;
PortP->State &= ~RIO_CARR_ON;
- PortP->ModemState &= ~MSVR1_CD;
+ PortP->ModemState &= ~RIOC_MSVR1_CD;
/*
** If the device was open as both a Modem and a tty line
** then we need to wimp out here, as the port has not really
@@ -453,7 +454,7 @@ int riotclose(void *ptr)
if (repeat_this-- <= 0) {
rv = -EINTR;
rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
goto close_end;
}
rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
@@ -492,8 +493,8 @@ int riotclose(void *ptr)
/* Can't call RIOShortCommand with the port locked. */
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
- if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ if (RIOShortCommand(p, PortP, RIOC_CLOSE, 1, 0) == RIO_FAIL) {
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
rio_spin_lock_irqsave(&PortP->portSem, flags);
goto close_end;
}
@@ -503,7 +504,7 @@ int riotclose(void *ptr)
try--;
if (time_after(jiffies, end_time)) {
rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
break;
}
rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN);
@@ -515,14 +516,14 @@ int riotclose(void *ptr)
}
if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
break;
}
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try);
- /* RIOPreemptiveCmd(p, PortP, FCLOSE); */
+ /* RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); */
/*
** 15.10.1998 ARG - ESIL 0761 part fix
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 3f9d0a9ac36d..f073c710ab8d 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -4,9 +4,9 @@
* Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com)
*
* This code is loosely based on the Linux serial driver, written by
- * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
- * programming info was obtained from various drivers for other OSes
- * (FreeBSD, ISC, etc), but no source code from those drivers were
+ * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
+ * programming info was obtained from various drivers for other OSes
+ * (FreeBSD, ISC, etc), but no source code from those drivers were
* directly included in this driver.
*
*
@@ -33,7 +33,7 @@
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ioport.h>
@@ -49,7 +49,7 @@
#include <linux/tty_flip.h>
#include <linux/spinlock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "riscom8.h"
#include "riscom8_reg.h"
@@ -57,15 +57,15 @@
/* Am I paranoid or not ? ;-) */
#define RISCOM_PARANOIA_CHECK
-/*
- * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals.
+/*
+ * Crazy InteliCom/8 boards sometimes have swapped CTS & DSR signals.
* You can slightly speed up things by #undefing the following option,
- * if you are REALLY sure that your board is correct one.
+ * if you are REALLY sure that your board is correct one.
*/
#define RISCOM_BRAIN_DAMAGED_CTS
-/*
+/*
* The following defines are mostly for testing purposes. But if you need
* some nice reporting in your syslog, you can define them also.
*/
@@ -112,7 +112,7 @@ static unsigned short rc_ioport[] = {
#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
-static inline int rc_paranoia_check(struct riscom_port const * port,
+static int rc_paranoia_check(struct riscom_port const *port,
char *name, const char *routine)
{
#ifdef RISCOM_PARANOIA_CHECK
@@ -134,52 +134,53 @@ static inline int rc_paranoia_check(struct riscom_port const * port,
}
/*
- *
+ *
* Service functions for RISCom/8 driver.
- *
+ *
*/
/* Get board number from pointer */
-static inline int board_No (struct riscom_board const * bp)
+static inline int board_No(struct riscom_board const *bp)
{
return bp - rc_board;
}
/* Get port number from pointer */
-static inline int port_No (struct riscom_port const * port)
+static inline int port_No(struct riscom_port const *port)
{
- return RC_PORT(port - rc_port);
+ return RC_PORT(port - rc_port);
}
/* Get pointer to board from pointer to port */
-static inline struct riscom_board * port_Board(struct riscom_port const * port)
+static inline struct riscom_board *port_Board(struct riscom_port const *port)
{
return &rc_board[RC_BOARD(port - rc_port)];
}
/* Input Byte from CL CD180 register */
-static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg)
+static inline unsigned char rc_in(struct riscom_board const *bp,
+ unsigned short reg)
{
return inb(bp->base + RC_TO_ISA(reg));
}
/* Output Byte to CL CD180 register */
-static inline void rc_out(struct riscom_board const * bp, unsigned short reg,
+static inline void rc_out(struct riscom_board const *bp, unsigned short reg,
unsigned char val)
{
outb(val, bp->base + RC_TO_ISA(reg));
}
/* Wait for Channel Command Register ready */
-static inline void rc_wait_CCR(struct riscom_board const * bp)
+static void rc_wait_CCR(struct riscom_board const *bp)
{
unsigned long delay;
/* FIXME: need something more descriptive then 100000 :) */
- for (delay = 100000; delay; delay--)
+ for (delay = 100000; delay; delay--)
if (!rc_in(bp, CD180_CCR))
return;
-
+
printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -187,11 +188,11 @@ static inline void rc_wait_CCR(struct riscom_board const * bp)
* RISCom/8 probe functions.
*/
-static inline int rc_request_io_range(struct riscom_board * const bp)
+static int rc_request_io_range(struct riscom_board * const bp)
{
int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
+
+ for (i = 0; i < RC_NIOPORT; i++)
if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
"RISCom/8")) {
goto out_release;
@@ -200,42 +201,42 @@ static inline int rc_request_io_range(struct riscom_board * const bp)
out_release:
printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
board_No(bp), bp->base);
- while(--i >= 0)
+ while (--i >= 0)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
return 1;
}
-static inline void rc_release_io_range(struct riscom_board * const bp)
+static void rc_release_io_range(struct riscom_board * const bp)
{
int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
+
+ for (i = 0; i < RC_NIOPORT; i++)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
}
-
+
/* Reset and setup CD180 chip */
-static void __init rc_init_CD180(struct riscom_board const * bp)
+static void __init rc_init_CD180(struct riscom_board const *bp)
{
unsigned long flags;
-
+
spin_lock_irqsave(&riscom_lock, flags);
- rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
- rc_wait_CCR(bp); /* Wait for CCR ready */
- rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
+ rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
+ rc_wait_CCR(bp); /* Wait for CCR ready */
+ rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
spin_unlock_irqrestore(&riscom_lock, flags);
- msleep(50); /* Delay 0.05 sec */
+ msleep(50); /* Delay 0.05 sec */
spin_lock_irqsave(&riscom_lock, flags);
- rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
- rc_out(bp, CD180_GICR, 0); /* Clear all bits */
- rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
- rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */
- rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */
-
+ rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
+ rc_out(bp, CD180_GICR, 0); /* Clear all bits */
+ rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
+ rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for tx intr */
+ rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for rx intr */
+
/* Setting up prescaler. We need 4 ticks per 1 ms */
rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
-
+
spin_unlock_irqrestore(&riscom_lock, flags);
}
@@ -245,12 +246,12 @@ static int __init rc_probe(struct riscom_board *bp)
unsigned char val1, val2;
int irqs = 0;
int retries;
-
+
bp->irq = 0;
if (rc_request_io_range(bp))
return 1;
-
+
/* Are the I/O ports here ? */
rc_out(bp, CD180_PPRL, 0x5a);
outb(0xff, 0x80);
@@ -258,34 +259,34 @@ static int __init rc_probe(struct riscom_board *bp)
rc_out(bp, CD180_PPRL, 0xa5);
outb(0x00, 0x80);
val2 = rc_in(bp, CD180_PPRL);
-
+
if ((val1 != 0x5a) || (val2 != 0xa5)) {
printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
board_No(bp), bp->base);
goto out_release;
}
-
+
/* It's time to find IRQ for this board */
- for (retries = 0; retries < 5 && irqs <= 0; retries++) {
+ for (retries = 0; retries < 5 && irqs <= 0; retries++) {
irqs = probe_irq_on();
- rc_init_CD180(bp); /* Reset CD180 chip */
- rc_out(bp, CD180_CAR, 2); /* Select port 2 */
+ rc_init_CD180(bp); /* Reset CD180 chip */
+ rc_out(bp, CD180_CAR, 2); /* Select port 2 */
rc_wait_CCR(bp);
- rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
- rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */
+ rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
+ rc_out(bp, CD180_IER, IER_TXRDY);/* Enable tx empty intr */
msleep(50);
irqs = probe_irq_off(irqs);
- val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
- val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
- rc_init_CD180(bp); /* Reset CD180 again */
-
+ val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
+ val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
+ rc_init_CD180(bp); /* Reset CD180 again */
+
if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
"found.\n", board_No(bp), bp->base);
goto out_release;
}
}
-
+
if (irqs <= 0) {
printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
"at 0x%03x.\n", board_No(bp), bp->base);
@@ -293,113 +294,112 @@ static int __init rc_probe(struct riscom_board *bp)
}
bp->irq = irqs;
bp->flags |= RC_BOARD_PRESENT;
-
+
printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
"0x%03x, IRQ %d.\n",
board_No(bp),
(rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
bp->base, bp->irq);
-
+
return 0;
out_release:
rc_release_io_range(bp);
return 1;
}
-/*
- *
+/*
+ *
* Interrupt processing routines.
- *
+ *
*/
-static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
- unsigned char const * what)
+static struct riscom_port *rc_get_port(struct riscom_board const *bp,
+ unsigned char const *what)
{
unsigned char channel;
- struct riscom_port * port;
-
+ struct riscom_port *port;
+
channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
if (channel < CD180_NCH) {
port = &rc_port[board_No(bp) * RC_NPORT + channel];
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED)
return port;
- }
}
- printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
+ printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
board_No(bp), what, channel);
return NULL;
}
-static inline void rc_receive_exc(struct riscom_board const * bp)
+static void rc_receive_exc(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char status;
unsigned char ch, flag;
-
- if (!(port = rc_get_port(bp, "Receive")))
+
+ port = rc_get_port(bp, "Receive");
+ if (port == NULL)
return;
tty = port->tty;
-
-#ifdef RC_REPORT_OVERRUN
+
+#ifdef RC_REPORT_OVERRUN
status = rc_in(bp, CD180_RCSR);
if (status & RCSR_OE)
port->overrun++;
status &= port->mark_mask;
-#else
+#else
status = rc_in(bp, CD180_RCSR) & port->mark_mask;
-#endif
+#endif
ch = rc_in(bp, CD180_RDR);
- if (!status) {
+ if (!status)
return;
- }
if (status & RCSR_TOUT) {
printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
- "Hardware problems ?\n",
+ "Hardware problems ?\n",
board_No(bp), port_No(port));
return;
-
+
} else if (status & RCSR_BREAK) {
printk(KERN_INFO "rc%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
flag = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
-
- } else if (status & RCSR_PE)
+
+ } else if (status & RCSR_PE)
flag = TTY_PARITY;
-
- else if (status & RCSR_FE)
+
+ else if (status & RCSR_FE)
flag = TTY_FRAME;
-
- else if (status & RCSR_OE)
+
+ else if (status & RCSR_OE)
flag = TTY_OVERRUN;
-
else
flag = TTY_NORMAL;
-
+
tty_insert_flip_char(tty, ch, flag);
tty_flip_buffer_push(tty);
}
-static inline void rc_receive(struct riscom_board const * bp)
+static void rc_receive(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char count;
-
- if (!(port = rc_get_port(bp, "Receive")))
+
+ port = rc_get_port(bp, "Receive");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
+
count = rc_in(bp, CD180_RDCR);
-
+
#ifdef RC_REPORT_FIFO
port->hits[count > 8 ? 9 : count]++;
-#endif
-
+#endif
+
while (count--) {
if (tty_buffer_request_room(tty, 1) == 0) {
printk(KERN_WARNING "rc%d: port %d: Working around "
@@ -412,26 +412,26 @@ static inline void rc_receive(struct riscom_board const * bp)
tty_flip_buffer_push(tty);
}
-static inline void rc_transmit(struct riscom_board const * bp)
+static void rc_transmit(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char count;
-
-
- if (!(port = rc_get_port(bp, "Transmit")))
+
+ port = rc_get_port(bp, "Transmit");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
- if (port->IER & IER_TXEMPTY) {
+
+ if (port->IER & IER_TXEMPTY) {
/* FIFO drained */
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXEMPTY;
rc_out(bp, CD180_IER, port->IER);
return;
}
-
+
if ((port->xmit_cnt <= 0 && !port->break_length)
|| tty->stopped || tty->hw_stopped) {
rc_out(bp, CD180_CAR, port_No(port));
@@ -439,7 +439,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
rc_out(bp, CD180_IER, port->IER);
return;
}
-
+
if (port->break_length) {
if (port->break_length > 0) {
if (port->COR2 & COR2_ETC) {
@@ -451,7 +451,8 @@ static inline void rc_transmit(struct riscom_board const * bp)
rc_out(bp, CD180_TDR, CD180_C_ESC);
rc_out(bp, CD180_TDR, CD180_C_DELAY);
rc_out(bp, CD180_TDR, count);
- if (!(port->break_length -= count))
+ port->break_length -= count;
+ if (port->break_length == 0)
port->break_length--;
} else {
rc_out(bp, CD180_TDR, CD180_C_ESC);
@@ -463,7 +464,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
}
return;
}
-
+
count = CD180_NFIFO;
do {
rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
@@ -471,7 +472,7 @@ static inline void rc_transmit(struct riscom_board const * bp)
if (--port->xmit_cnt <= 0)
break;
} while (--count > 0);
-
+
if (port->xmit_cnt <= 0) {
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXRDY;
@@ -481,25 +482,26 @@ static inline void rc_transmit(struct riscom_board const * bp)
tty_wakeup(tty);
}
-static inline void rc_check_modem(struct riscom_board const * bp)
+static void rc_check_modem(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char mcr;
-
- if (!(port = rc_get_port(bp, "Modem")))
+
+ port = rc_get_port(bp, "Modem");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
+
mcr = rc_in(bp, CD180_MCR);
- if (mcr & MCR_CDCHG) {
- if (rc_in(bp, CD180_MSVR) & MSVR_CD)
+ if (mcr & MCR_CDCHG) {
+ if (rc_in(bp, CD180_MSVR) & MSVR_CD)
wake_up_interruptible(&port->open_wait);
else
tty_hangup(tty);
}
-
+
#ifdef RISCOM_BRAIN_DAMAGED_CTS
if (mcr & MCR_CTSCHG) {
if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
@@ -526,13 +528,13 @@ static inline void rc_check_modem(struct riscom_board const * bp)
rc_out(bp, CD180_IER, port->IER);
}
#endif /* RISCOM_BRAIN_DAMAGED_CTS */
-
+
/* Clear change bits */
rc_out(bp, CD180_MCR, 0);
}
/* The main interrupt processing routine */
-static irqreturn_t rc_interrupt(int dummy, void * dev_id)
+static irqreturn_t rc_interrupt(int dummy, void *dev_id)
{
unsigned char status;
unsigned char ack;
@@ -547,13 +549,11 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id)
(RC_BSR_TOUT | RC_BSR_TINT |
RC_BSR_MINT | RC_BSR_RINT))) {
handled = 1;
- if (status & RC_BSR_TOUT)
+ if (status & RC_BSR_TOUT)
printk(KERN_WARNING "rc%d: Got timeout. Hardware "
"error?\n", board_No(bp));
-
else if (status & RC_BSR_RINT) {
ack = rc_in(bp, RC_ACK_RINT);
-
if (ack == (RC_ID | GIVR_IT_RCV))
rc_receive(bp);
else if (ack == (RC_ID | GIVR_IT_REXC))
@@ -562,29 +562,23 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id)
printk(KERN_WARNING "rc%d: Bad receive ack "
"0x%02x.\n",
board_No(bp), ack);
-
} else if (status & RC_BSR_TINT) {
ack = rc_in(bp, RC_ACK_TINT);
-
if (ack == (RC_ID | GIVR_IT_TX))
rc_transmit(bp);
else
printk(KERN_WARNING "rc%d: Bad transmit ack "
"0x%02x.\n",
board_No(bp), ack);
-
} else /* if (status & RC_BSR_MINT) */ {
ack = rc_in(bp, RC_ACK_MINT);
-
- if (ack == (RC_ID | GIVR_IT_MODEM))
+ if (ack == (RC_ID | GIVR_IT_MODEM))
rc_check_modem(bp);
else
printk(KERN_WARNING "rc%d: Bad modem ack "
"0x%02x.\n",
board_No(bp), ack);
-
- }
-
+ }
rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
}
@@ -596,24 +590,24 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id)
*/
/* Called with disabled interrupts */
-static int rc_setup_board(struct riscom_board * bp)
+static int rc_setup_board(struct riscom_board *bp)
{
int error;
- if (bp->flags & RC_BOARD_ACTIVE)
+ if (bp->flags & RC_BOARD_ACTIVE)
return 0;
-
+
error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
"RISCom/8", bp);
- if (error)
+ if (error)
return error;
-
+
rc_out(bp, RC_CTOUT, 0); /* Just in case */
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
-
+
bp->flags |= RC_BOARD_ACTIVE;
-
+
return 0;
}
@@ -622,40 +616,40 @@ static void rc_shutdown_board(struct riscom_board *bp)
{
if (!(bp->flags & RC_BOARD_ACTIVE))
return;
-
+
bp->flags &= ~RC_BOARD_ACTIVE;
-
+
free_irq(bp->irq, NULL);
-
+
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
-
+
}
/*
- * Setting up port characteristics.
+ * Setting up port characteristics.
* Must be called with disabled interrupts
*/
static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
{
- struct tty_struct *tty;
+ struct tty_struct *tty = port->tty;
unsigned long baud;
long tmp;
unsigned char cor1 = 0, cor3 = 0;
unsigned char mcor1 = 0, mcor2 = 0;
-
- if (!(tty = port->tty) || !tty->termios)
+
+ if (tty == NULL || tty->termios == NULL)
return;
port->IER = 0;
port->COR2 = 0;
port->MSVR = MSVR_RTS;
-
+
baud = tty_get_baud_rate(tty);
-
+
/* Select port on the board */
rc_out(bp, CD180_CAR, port_No(port));
-
+
if (!baud) {
/* Drop DTR & exit */
bp->DTR |= (1u << port_No(port));
@@ -666,69 +660,68 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
bp->DTR &= ~(1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
}
-
+
/*
- * Now we must calculate some speed depended things
+ * Now we must calculate some speed depended things
*/
-
+
/* Set baud rate for port */
tmp = (((RC_OSCFREQ + baud/2) / baud +
CD180_TPC/2) / CD180_TPC);
- rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
- rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
- rc_out(bp, CD180_RBPRL, tmp & 0xff);
+ rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
+ rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
+ rc_out(bp, CD180_RBPRL, tmp & 0xff);
rc_out(bp, CD180_TBPRL, tmp & 0xff);
-
+
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;
+ 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 = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
tmp = (tmp > 0xff) ? 0xff : tmp;
rc_out(bp, CD180_RTPR, tmp);
-
- switch (C_CSIZE(tty)) {
- case CS5:
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
cor1 |= COR1_5BITS;
break;
- case CS6:
+ case CS6:
cor1 |= COR1_6BITS;
break;
- case CS7:
+ case CS7:
cor1 |= COR1_7BITS;
break;
- case CS8:
+ case CS8:
cor1 |= COR1_8BITS;
break;
}
-
- if (C_CSTOPB(tty))
+ if (C_CSTOPB(tty))
cor1 |= COR1_2SB;
-
+
cor1 |= COR1_IGNORE;
- if (C_PARENB(tty)) {
+ if (C_PARENB(tty)) {
cor1 |= COR1_NORMPAR;
- if (C_PARODD(tty))
+ if (C_PARODD(tty))
cor1 |= COR1_ODDP;
- if (I_INPCK(tty))
+ if (I_INPCK(tty))
cor1 &= ~COR1_IGNORE;
}
/* Set marking of some errors */
port->mark_mask = RCSR_OE | RCSR_TOUT;
- if (I_INPCK(tty))
+ if (I_INPCK(tty))
port->mark_mask |= RCSR_FE | RCSR_PE;
- if (I_BRKINT(tty) || I_PARMRK(tty))
+ if (I_BRKINT(tty) || I_PARMRK(tty))
port->mark_mask |= RCSR_BREAK;
- if (I_IGNPAR(tty))
+ if (I_IGNPAR(tty))
port->mark_mask &= ~(RCSR_FE | RCSR_PE);
- if (I_IGNBRK(tty)) {
+ if (I_IGNBRK(tty)) {
port->mark_mask &= ~RCSR_BREAK;
- if (I_IGNPAR(tty))
+ if (I_IGNPAR(tty))
/* Real raw mode. Ignore all */
port->mark_mask &= ~RCSR_OE;
}
@@ -738,7 +731,8 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
port->IER |= IER_DSR | IER_CTS;
mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
- tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
+ tty->hw_stopped = !(rc_in(bp, CD180_MSVR) &
+ (MSVR_CTS|MSVR_DSR));
#else
port->COR2 |= COR2_CTSAE;
#endif
@@ -761,13 +755,13 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
mcor1 |= MCOR1_CDZD;
mcor2 |= MCOR2_CDOD;
}
-
- if (C_CREAD(tty))
+
+ if (C_CREAD(tty))
/* Enable receiver */
port->IER |= IER_RXD;
-
+
/* Set input FIFO size (1-8 bytes) */
- cor3 |= RISCOM_RXFIFO;
+ cor3 |= RISCOM_RXFIFO;
/* Setting up CD180 channel registers */
rc_out(bp, CD180_COR1, cor1);
rc_out(bp, CD180_COR2, port->COR2);
@@ -791,36 +785,30 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
{
unsigned long flags;
-
+
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)))
+ unsigned long tmp = get_zeroed_page(GFP_KERNEL);
+ if (tmp == 0)
return -ENOMEM;
-
- if (port->xmit_buf) {
+ if (port->xmit_buf)
free_page(tmp);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) tmp;
+ else
+ port->xmit_buf = (unsigned char *) tmp;
}
-
spin_lock_irqsave(&riscom_lock, flags);
- if (port->tty)
+ if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
- if (port->count == 1)
+ if (port->count == 1)
bp->count++;
-
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
rc_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
-
+
spin_unlock_irqrestore(&riscom_lock, flags);
return 0;
}
@@ -829,38 +817,39 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
{
struct tty_struct *tty;
-
- if (!(port->flags & ASYNC_INITIALIZED))
+
+ if (!(port->flags & ASYNC_INITIALIZED))
return;
-
+
#ifdef RC_REPORT_OVERRUN
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
board_No(bp), port_No(port), port->overrun);
-#endif
+#endif
#ifdef RC_REPORT_FIFO
{
int i;
-
+
printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
board_No(bp), port_No(port));
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < 10; i++)
printk("%ld ", port->hits[i]);
- }
printk("].\n");
}
-#endif
+#endif
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
}
- if (!(tty = port->tty) || C_HUPCL(tty)) {
+ tty = port->tty;
+
+ if (tty == NULL || C_HUPCL(tty)) {
/* Drop DTR */
bp->DTR |= (1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
}
-
- /* Select port */
+
+ /* Select port */
rc_out(bp, CD180_CAR, port_No(port));
/* Reset port */
rc_wait_CCR(bp);
@@ -868,28 +857,26 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
/* Disable all interrupts from this port */
port->IER = 0;
rc_out(bp, CD180_IER, port->IER);
-
- if (tty)
+
+ if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
port->flags &= ~ASYNC_INITIALIZED;
-
+
if (--bp->count < 0) {
printk(KERN_INFO "rc%d: rc_shutdown_port: "
"bad board count: %d\n",
board_No(bp), bp->count);
bp->count = 0;
}
-
/*
* If this is the last opened port on the board
* shutdown whole board
*/
- if (!bp->count)
+ if (!bp->count)
rc_shutdown_board(bp);
}
-
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct riscom_port *port)
{
DECLARE_WAITQUEUE(wait, current);
@@ -921,7 +908,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (C_CLOCAL(tty))
+ if (C_CLOCAL(tty))
do_clocal = 1;
/*
@@ -959,7 +946,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
break;
}
if (!(port->flags & ASYNC_CLOSING) &&
@@ -978,50 +965,63 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
port->blocked_open--;
if (retval)
return retval;
-
+
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
-}
+}
-static int rc_open(struct tty_struct * tty, struct file * filp)
+static int rc_open(struct tty_struct *tty, struct file *filp)
{
int board;
int error;
- struct riscom_port * port;
- struct riscom_board * bp;
-
+ struct riscom_port *port;
+ struct riscom_board *bp;
+
board = RC_BOARD(tty->index);
if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
return -ENODEV;
-
+
bp = &rc_board[board];
port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
if (rc_paranoia_check(port, tty->name, "rc_open"))
return -ENODEV;
-
- if ((error = rc_setup_board(bp)))
+
+ error = rc_setup_board(bp);
+ if (error)
return error;
-
+
port->count++;
tty->driver_data = port;
port->tty = tty;
-
- if ((error = rc_setup_port(bp, port)))
- return error;
-
- if ((error = block_til_ready(tty, filp, port)))
- return error;
-
- return 0;
+
+ error = rc_setup_port(bp, port);
+ if (error == 0)
+ error = block_til_ready(tty, filp, port);
+ return error;
}
-static void rc_close(struct tty_struct * tty, struct file * filp)
+static void rc_flush_buffer(struct tty_struct *tty)
+{
+ struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+ unsigned long flags;
+
+ if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
+ return;
+
+ spin_lock_irqsave(&riscom_lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
+ tty_wakeup(tty);
+}
+
+static void rc_close(struct tty_struct *tty, struct file *filp)
{
struct riscom_port *port = (struct riscom_port *) tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
unsigned long timeout;
-
+
if (!port || rc_paranoia_check(port, tty->name, "close"))
return;
@@ -1029,7 +1029,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
if (tty_hung_up_p(filp))
goto out;
-
+
bp = port_Board(port);
if ((tty->count == 1) && (port->count != 1)) {
printk(KERN_INFO "rc%d: rc_close: bad port count;"
@@ -1047,7 +1047,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
goto out;
port->flags |= ASYNC_CLOSING;
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
@@ -1070,24 +1070,22 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
- timeout = jiffies+HZ;
- while(port->IER & IER_TXEMPTY) {
+ timeout = jiffies + HZ;
+ while (port->IER & IER_TXEMPTY) {
msleep_interruptible(jiffies_to_msecs(port->timeout));
if (time_after(jiffies, timeout))
break;
}
}
rc_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rc_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
port->tty = NULL;
if (port->blocked_open) {
- if (port->close_delay) {
+ 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);
@@ -1097,17 +1095,17 @@ out:
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static int rc_write(struct tty_struct * tty,
+static int rc_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
int c, total = 0;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_write"))
return 0;
-
+
bp = port_Board(port);
if (!tty || !port->xmit_buf)
@@ -1144,38 +1142,41 @@ static int rc_write(struct tty_struct * tty,
return total;
}
-static void rc_put_char(struct tty_struct * tty, unsigned char ch)
+static int rc_put_char(struct tty_struct *tty, unsigned char ch)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (rc_paranoia_check(port, tty->name, "rc_put_char"))
- return;
+ return 0;
if (!tty || !port->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&riscom_lock, flags);
-
+
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
goto out;
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
+ ret = 1;
out:
spin_unlock_irqrestore(&riscom_lock, flags);
+ return ret;
}
-static void rc_flush_chars(struct tty_struct * tty)
+static void rc_flush_chars(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
return;
-
+
if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
!port->xmit_buf)
return;
@@ -1189,11 +1190,11 @@ static void rc_flush_chars(struct tty_struct * tty)
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static int rc_write_room(struct tty_struct * tty)
+static int rc_write_room(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
int ret;
-
+
if (rc_paranoia_check(port, tty->name, "rc_write_room"))
return 0;
@@ -1206,39 +1207,22 @@ static int rc_write_room(struct tty_struct * tty)
static int rc_chars_in_buffer(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
-
+
if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
return 0;
-
- return port->xmit_cnt;
-}
-
-static void rc_flush_buffer(struct tty_struct *tty)
-{
- struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- unsigned long flags;
-
- if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
- return;
-
- spin_lock_irqsave(&riscom_lock, flags);
-
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&riscom_lock, flags);
-
- tty_wakeup(tty);
+ return port->xmit_cnt;
}
static int rc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- struct riscom_board * bp;
+ struct riscom_board *bp;
unsigned char status;
unsigned int result;
unsigned long flags;
- if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+ if (rc_paranoia_check(port, tty->name, __func__))
return -ENODEV;
bp = port_Board(port);
@@ -1266,7 +1250,7 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
unsigned long flags;
struct riscom_board *bp;
- if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+ if (rc_paranoia_check(port, tty->name, __func__))
return -ENODEV;
bp = port_Board(port);
@@ -1292,11 +1276,11 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-static inline void rc_send_break(struct riscom_port * port, unsigned long length)
+static void rc_send_break(struct riscom_port *port, unsigned long length)
{
struct riscom_board *bp = port_Board(port);
unsigned long flags;
-
+
spin_lock_irqsave(&riscom_lock, flags);
port->break_length = RISCOM_TPS / HZ * length;
@@ -1312,17 +1296,17 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static inline int rc_set_serial_info(struct riscom_port * port,
- struct serial_struct __user * newinfo)
+static int rc_set_serial_info(struct riscom_port *port,
+ struct serial_struct __user *newinfo)
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
int change_speed;
-
+
if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
return -EFAULT;
-
-#if 0
+
+#if 0
if ((tmp.irq != bp->irq) ||
(tmp.port != bp->base) ||
(tmp.type != PORT_CIRRUS) ||
@@ -1331,16 +1315,16 @@ static inline int rc_set_serial_info(struct riscom_port * port,
(tmp.xmit_fifo_size != CD180_NFIFO) ||
(tmp.flags & ~RISCOM_LEGAL_FLAGS))
return -EINVAL;
-#endif
-
+#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)))
+ (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(tmp.flags & ASYNC_USR_MASK));
@@ -1360,12 +1344,12 @@ static inline int rc_set_serial_info(struct riscom_port * port,
return 0;
}
-static inline int rc_get_serial_info(struct riscom_port * port,
+static int rc_get_serial_info(struct riscom_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
-
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_CIRRUS;
tmp.line = port - rc_port;
@@ -1379,19 +1363,18 @@ static inline int rc_get_serial_info(struct riscom_port * port,
return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
-static int rc_ioctl(struct tty_struct * tty, struct file * filp,
+static int rc_ioctl(struct tty_struct *tty, struct file *filp,
unsigned int cmd, unsigned long arg)
-
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
void __user *argp = (void __user *)arg;
- int retval;
-
+ int retval = 0;
+
if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
return -ENODEV;
-
+
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
return retval;
@@ -1399,45 +1382,40 @@ static int rc_ioctl(struct tty_struct * tty, struct file * filp,
if (!arg)
rc_send_break(port, HZ/4); /* 1/4 second */
break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
break;
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg,(unsigned __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
+ case TIOCGSERIAL:
+ lock_kernel();
+ retval = rc_get_serial_info(port, argp);
+ unlock_kernel();
break;
- case TIOCGSERIAL:
- return rc_get_serial_info(port, argp);
- case TIOCSSERIAL:
- return rc_set_serial_info(port, argp);
- default:
- return -ENOIOCTLCMD;
+ case TIOCSSERIAL:
+ lock_kernel();
+ retval = rc_set_serial_info(port, argp);
+ unlock_kernel();
+ break;
+ default:
+ retval = -ENOIOCTLCMD;
}
- return 0;
+ return retval;
}
-static void rc_throttle(struct tty_struct * tty)
+static void rc_throttle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_throttle"))
return;
-
bp = port_Board(port);
spin_lock_irqsave(&riscom_lock, flags);
-
port->MSVR &= ~MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1446,23 +1424,20 @@ static void rc_throttle(struct tty_struct * tty)
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_unthrottle(struct tty_struct * tty)
+static void rc_unthrottle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
return;
-
bp = port_Board(port);
-
- spin_lock_irqsave(&riscom_lock, flags);
+ spin_lock_irqsave(&riscom_lock, flags);
port->MSVR |= MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1471,62 +1446,58 @@ static void rc_unthrottle(struct tty_struct * tty)
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_stop(struct tty_struct * tty)
+static void rc_stop(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_stop"))
return;
-
+
bp = port_Board(port);
-
- spin_lock_irqsave(&riscom_lock, flags);
+ spin_lock_irqsave(&riscom_lock, flags);
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_start(struct tty_struct * tty)
+static void rc_start(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_start"))
return;
-
+
bp = port_Board(port);
-
+
spin_lock_irqsave(&riscom_lock, flags);
- if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
+ if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_hangup(struct tty_struct * tty)
+static void rc_hangup(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
-
+
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
return;
-
+
bp = port_Board(port);
-
+
rc_shutdown_port(bp, port);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -1534,17 +1505,14 @@ static void rc_hangup(struct tty_struct * tty)
wake_up_interruptible(&port->open_wait);
}
-static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
+static void rc_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
return;
-
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(port_Board(port), port);
@@ -1583,9 +1551,9 @@ static int __init rc_init_drivers(void)
int i;
riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
- if (!riscom_driver)
+ if (!riscom_driver)
return -ENOMEM;
-
+
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
riscom_driver->major = RISCOM8_NORMAL_MAJOR;
@@ -1598,23 +1566,21 @@ static int __init rc_init_drivers(void)
riscom_driver->init_termios.c_ospeed = 9600;
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
- if ((error = tty_register_driver(riscom_driver))) {
+ error = tty_register_driver(riscom_driver);
+ if (error != 0) {
put_tty_driver(riscom_driver);
printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
- "error = %d\n",
- error);
+ "error = %d\n", error);
return 1;
}
-
memset(rc_port, 0, sizeof(rc_port));
for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
rc_port[i].magic = RISCOM8_MAGIC;
- rc_port[i].close_delay = 50 * HZ/100;
- rc_port[i].closing_wait = 3000 * HZ/100;
+ rc_port[i].close_delay = 50 * HZ / 100;
+ rc_port[i].closing_wait = 3000 * HZ / 100;
init_waitqueue_head(&rc_port[i].open_wait);
init_waitqueue_head(&rc_port[i].close_wait);
}
-
return 0;
}
@@ -1627,13 +1593,13 @@ static void rc_release_drivers(void)
#ifndef MODULE
/*
* 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.
*
- */
+ */
static int __init riscom8_setup(char *str)
{
int ints[RC_NBOARD];
@@ -1644,7 +1610,7 @@ static int __init riscom8_setup(char *str)
for (i = 0; i < RC_NBOARD; i++) {
if (i < ints[0])
rc_board[i].base = ints[i+1];
- else
+ else
rc_board[i].base = 0;
}
return 1;
@@ -1659,8 +1625,8 @@ static char banner[] __initdata =
static char no_boards_msg[] __initdata =
KERN_INFO "rc: No RISCom/8 boards detected.\n";
-/*
- * This routine must be called by kernel at boot time
+/*
+ * This routine must be called by kernel at boot time
*/
static int __init riscom8_init(void)
{
@@ -1669,13 +1635,12 @@ static int __init riscom8_init(void)
printk(banner);
- if (rc_init_drivers())
+ if (rc_init_drivers())
return -EIO;
- for (i = 0; i < RC_NBOARD; i++)
- if (rc_board[i].base && !rc_probe(&rc_board[i]))
+ for (i = 0; i < RC_NBOARD; i++)
+ if (rc_board[i].base && !rc_probe(&rc_board[i]))
found++;
-
if (!found) {
rc_release_drivers();
printk(no_boards_msg);
@@ -1702,13 +1667,13 @@ MODULE_LICENSE("GPL");
* by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
*
*/
-static int __init riscom8_init_module (void)
+static int __init riscom8_init_module(void)
{
#ifdef MODULE
int i;
if (iobase || iobase1 || iobase2 || iobase3) {
- for(i = 0; i < RC_NBOARD; i++)
+ for (i = 0; i < RC_NBOARD; i++)
rc_board[i].base = 0;
}
@@ -1724,18 +1689,17 @@ static int __init riscom8_init_module (void)
return riscom8_init();
}
-
-static void __exit riscom8_exit_module (void)
+
+static void __exit riscom8_exit_module(void)
{
int i;
-
+
rc_release_drivers();
- for (i = 0; i < RC_NBOARD; i++)
- if (rc_board[i].flags & RC_BOARD_PRESENT)
+ for (i = 0; i < RC_NBOARD; i++)
+ if (rc_board[i].flags & RC_BOARD_PRESENT)
rc_release_io_range(&rc_board[i]);
-
+
}
module_init(riscom8_init_module);
module_exit(riscom8_exit_module);
-
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index f585bc8579e9..743dc80a9325 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -449,7 +449,8 @@ static void rp_do_transmit(struct r_port *info)
while (1) {
if (tty->stopped || tty->hw_stopped)
break;
- c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail));
+ c = min(info->xmit_fifo_room, info->xmit_cnt);
+ c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
if (c <= 0 || info->xmit_fifo_room <= 0)
break;
sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
@@ -1433,29 +1434,38 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file,
{
struct r_port *info = (struct r_port *) tty->driver_data;
void __user *argp = (void __user *)arg;
+ int ret = 0;
if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
return -ENXIO;
+ lock_kernel();
+
switch (cmd) {
case RCKP_GET_STRUCT:
if (copy_to_user(argp, info, sizeof (struct r_port)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
case RCKP_GET_CONFIG:
- return get_config(info, argp);
+ ret = get_config(info, argp);
+ break;
case RCKP_SET_CONFIG:
- return set_config(info, argp);
+ ret = set_config(info, argp);
+ break;
case RCKP_GET_PORTS:
- return get_ports(info, argp);
+ ret = get_ports(info, argp);
+ break;
case RCKP_RESET_RM2:
- return reset_rm2(info, argp);
+ ret = reset_rm2(info, argp);
+ break;
case RCKP_GET_VERSION:
- return get_version(info, argp);
+ ret = get_version(info, argp);
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
- return 0;
+ unlock_kernel();
+ return ret;
}
static void rp_send_xchar(struct tty_struct *tty, char ch)
@@ -1575,6 +1585,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
jiffies);
printk(KERN_INFO "cps=%d...\n", info->cps);
#endif
+ lock_kernel();
while (1) {
txcnt = sGetTxCnt(cp);
if (!txcnt) {
@@ -1602,6 +1613,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
__set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
#endif
@@ -1651,14 +1663,14 @@ static void rp_hangup(struct tty_struct *tty)
* writing routines will write directly to transmit FIFO.
* Write buffer and counters protected by spinlocks
*/
-static void rp_put_char(struct tty_struct *tty, unsigned char ch)
+static int rp_put_char(struct tty_struct *tty, unsigned char ch)
{
struct r_port *info = (struct r_port *) tty->driver_data;
CHANNEL_t *cp;
unsigned long flags;
if (rocket_paranoia_check(info, "rp_put_char"))
- return;
+ return 0;
/*
* Grab the port write mutex, locking out other processes that try to
@@ -1687,6 +1699,7 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
}
spin_unlock_irqrestore(&info->slock, flags);
mutex_unlock(&info->write_mtx);
+ return 1;
}
/*
@@ -1749,10 +1762,10 @@ static int rp_write(struct tty_struct *tty,
/* Write remaining data into the port's xmit_buf */
while (1) {
- if (!info->tty) /* Seemingly obligatory check... */
+ if (!info->tty) /* Seemingly obligatory check... */
goto end;
-
- c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head));
+ c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
+ c = min(c, XMIT_BUF_SIZE - info->xmit_head);
if (c <= 0)
break;
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index b01d38125a8f..143cc432fdb2 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -55,7 +55,7 @@ static inline void sOutW(unsigned short port, unsigned short value)
static inline void out32(unsigned short port, Byte_t *p)
{
- u32 value = le32_to_cpu(get_unaligned((__le32 *)p));
+ u32 value = get_unaligned_le32(p);
#ifdef ROCKET_DEBUG_IO
printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value);
#endif
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index e2ec2ee4cf79..5f80a9dff573 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -1069,10 +1069,8 @@ no_irq:
}
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("driver/rtc", 0, NULL);
- if (ent)
- ent->proc_fops = &rtc_proc_fops;
- else
+ ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops);
+ if (!ent)
printk(KERN_WARNING "rtc: Failed to register with procfs.\n");
#endif
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index df8cd0ca97eb..3b23270eaa65 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1060,7 +1060,7 @@ static void config_setup(struct cyclades_port *info)
} /* config_setup */
-static void cy_put_char(struct tty_struct *tty, unsigned char ch)
+static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
@@ -1070,21 +1070,22 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
local_irq_save(flags);
if (info->xmit_cnt >= PAGE_SIZE - 1) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= PAGE_SIZE - 1;
info->xmit_cnt++;
local_irq_restore(flags);
+ return 1;
} /* cy_put_char */
static void cy_flush_chars(struct tty_struct *tty)
@@ -1539,6 +1540,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
#endif
+ lock_kernel();
+
switch (cmd) {
case CYGETMON:
ret_val = get_mon_info(info, argp);
@@ -1584,18 +1587,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
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;
@@ -1605,6 +1596,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
default:
ret_val = -ENOIOCTLCMD;
}
+ unlock_kernel();
#ifdef SERIAL_DEBUG_OTHER
printk("cy_ioctl done\n");
@@ -1683,8 +1675,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
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);
+ cy_flush_buffer(tty);
tty_ldisc_flush(tty);
info->tty = NULL;
if (info->blocked_open) {
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index b9c1dba6bd01..8fe099a41065 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -80,7 +80,7 @@ scdrv_open(struct inode *inode, struct file *file)
sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
if (sd == NULL) {
printk("%s: couldn't allocate subchannel data\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -90,7 +90,7 @@ scdrv_open(struct inode *inode, struct file *file)
if (sd->sd_subch < 0) {
kfree(sd);
- printk("%s: couldn't allocate subchannel\n", __FUNCTION__);
+ printk("%s: couldn't allocate subchannel\n", __func__);
return -EBUSY;
}
@@ -110,7 +110,7 @@ scdrv_open(struct inode *inode, struct file *file)
if (rv) {
ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
kfree(sd);
- printk("%s: irq request failed (%d)\n", __FUNCTION__, rv);
+ printk("%s: irq request failed (%d)\n", __func__, rv);
return -EBUSY;
}
@@ -215,7 +215,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
*/
if (count < len) {
pr_debug("%s: only accepting %d of %d bytes\n",
- __FUNCTION__, (int) count, len);
+ __func__, (int) count, len);
}
len = min((int) count, len);
if (copy_to_user(buf, sd->sd_rb, len))
@@ -384,7 +384,7 @@ scdrv_init(void)
if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
SYSCTL_BASENAME) < 0) {
printk("%s: failed to register SN system controller device\n",
- __FUNCTION__);
+ __func__);
return -ENODEV;
}
snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
@@ -403,7 +403,7 @@ scdrv_init(void)
GFP_KERNEL);
if (!scd) {
printk("%s: failed to allocate device info"
- "for %s/%s\n", __FUNCTION__,
+ "for %s/%s\n", __func__,
SYSCTL_BASENAME, devname);
continue;
}
@@ -412,7 +412,7 @@ scdrv_init(void)
scd->scd_nasid = cnodeid_to_nasid(cnode);
if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
printk("%s: failed to allocate driver buffer"
- "(%s%s)\n", __FUNCTION__,
+ "(%s%s)\n", __func__,
SYSCTL_BASENAME, devname);
kfree(scd);
continue;
@@ -424,7 +424,7 @@ scdrv_init(void)
("%s: failed to initialize SAL for"
" system controller communication"
" (%s/%s): outdated PROM?\n",
- __FUNCTION__, SYSCTL_BASENAME, devname);
+ __func__, SYSCTL_BASENAME, devname);
kfree(scd);
kfree(salbuf);
continue;
@@ -435,7 +435,7 @@ scdrv_init(void)
if (cdev_add(&scd->scd_cdev, dev, 1)) {
printk("%s: failed to register system"
" controller device (%s%s)\n",
- __FUNCTION__, SYSCTL_BASENAME, devname);
+ __func__, SYSCTL_BASENAME, devname);
kfree(scd);
kfree(salbuf);
continue;
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index 1b75b0b7d542..55a95892ccf9 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/sn/sn_sal.h>
#include <asm/unaligned.h>
#include "snsc.h"
@@ -63,16 +63,13 @@ static int
scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
{
char *desc_end;
- __be32 from_buf;
/* record event source address */
- from_buf = get_unaligned((__be32 *)event);
- *src = be32_to_cpup(&from_buf);
+ *src = get_unaligned_be32(event);
event += 4; /* move on to event code */
/* record the system controller's event code */
- from_buf = get_unaligned((__be32 *)event);
- *code = be32_to_cpup(&from_buf);
+ *code = get_unaligned_be32(event);
event += 4; /* move on to event arguments */
/* how many arguments are in the packet? */
@@ -86,8 +83,7 @@ scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
/* not an integer argument, so give up */
return -1;
}
- from_buf = get_unaligned((__be32 *)event);
- *esp_code = be32_to_cpup(&from_buf);
+ *esp_code = get_unaligned_be32(event);
event += 4;
/* parse out the event description */
@@ -275,7 +271,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
if (event_sd == NULL) {
printk(KERN_WARNING "%s: couldn't allocate subchannel info"
- " for event monitoring\n", __FUNCTION__);
+ " for event monitoring\n", __func__);
return;
}
@@ -289,7 +285,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
if (event_sd->sd_subch < 0) {
kfree(event_sd);
printk(KERN_WARNING "%s: couldn't open event subchannel\n",
- __FUNCTION__);
+ __func__);
return;
}
@@ -299,7 +295,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
"system controller events", event_sd);
if (rv) {
printk(KERN_WARNING "%s: irq request failed (%d)\n",
- __FUNCTION__, rv);
+ __func__, rv);
ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
kfree(event_sd);
return;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index c03ad164c39a..58533de59027 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -506,7 +506,7 @@ static struct sonypi_device {
while (--n && (command)) \
udelay(1); \
if (!n && (verbose || !quiet)) \
- printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+ printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \
}
#ifdef CONFIG_ACPI
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 4b5b5b78acb4..2ee4d9893757 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -131,8 +131,8 @@ static int sx_rxfifo = SPECIALIX_RXFIFO;
#define SX_DEBUG_FIFO 0x0800
-#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
-#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __FUNCTION__)
+#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__func__)
+#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __func__)
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
@@ -874,7 +874,7 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
spin_lock_irqsave(&bp->lock, flags);
- dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
+ dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
if (!(bp->flags & SX_BOARD_ACTIVE)) {
dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", bp->irq);
spin_unlock_irqrestore(&bp->lock, flags);
@@ -1504,6 +1504,27 @@ static int sx_open(struct tty_struct * tty, struct file * filp)
return 0;
}
+static void sx_flush_buffer(struct tty_struct *tty)
+{
+ struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+ unsigned long flags;
+ struct specialix_board * bp;
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+ func_exit();
+ return;
+ }
+
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
+ tty_wakeup(tty);
+
+ func_exit();
+}
static void sx_close(struct tty_struct * tty, struct file * filp)
{
@@ -1597,8 +1618,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
sx_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ sx_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
@@ -1670,7 +1690,7 @@ static int sx_write(struct tty_struct * tty,
}
-static void sx_put_char(struct tty_struct * tty, unsigned char ch)
+static int sx_put_char(struct tty_struct * tty, unsigned char ch)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
@@ -1680,12 +1700,12 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
func_exit();
- return;
+ return 0;
}
dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
if (!port->xmit_buf) {
func_exit();
- return;
+ return 0;
}
bp = port_Board(port);
spin_lock_irqsave(&port->lock, flags);
@@ -1695,7 +1715,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
spin_unlock_irqrestore(&port->lock, flags);
dprintk (SX_DEBUG_TX, "Exit size\n");
func_exit();
- return;
+ return 0;
}
dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
port->xmit_buf[port->xmit_head++] = ch;
@@ -1704,6 +1724,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
spin_unlock_irqrestore(&port->lock, flags);
func_exit();
+ return 1;
}
@@ -1770,28 +1791,6 @@ static int sx_chars_in_buffer(struct tty_struct *tty)
}
-static void sx_flush_buffer(struct tty_struct *tty)
-{
- struct specialix_port *port = (struct specialix_port *)tty->driver_data;
- unsigned long flags;
- struct specialix_board * bp;
-
- func_enter();
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
- func_exit();
- return;
- }
-
- bp = port_Board(port);
- spin_lock_irqsave(&port->lock, flags);
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&port->lock, flags);
- tty_wakeup(tty);
-
- func_exit();
-}
-
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
@@ -1803,7 +1802,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
func_enter();
- if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ if (sx_paranoia_check(port, tty->name, __func__)) {
func_exit();
return -ENODEV;
}
@@ -1845,7 +1844,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
func_enter();
- if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ if (sx_paranoia_check(port, tty->name, __func__)) {
func_exit();
return -ENODEV;
}
@@ -1922,29 +1921,13 @@ static inline int sx_set_serial_info(struct specialix_port * port,
int change_speed;
func_enter();
- /*
- if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) {
- func_exit();
- return -EFAULT;
- }
- */
+
if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
func_enter();
return -EFAULT;
}
-#if 0
- if ((tmp.irq != bp->irq) ||
- (tmp.port != bp->base) ||
- (tmp.type != PORT_CIRRUS) ||
- (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
- (tmp.custom_divisor != 0) ||
- (tmp.xmit_fifo_size != CD186x_NFIFO) ||
- (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
- func_exit();
- return -EINVAL;
- }
-#endif
+ lock_kernel();
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
(tmp.flags & ASYNC_SPD_MASK));
@@ -1956,6 +1939,7 @@ static inline int sx_set_serial_info(struct specialix_port * port,
((tmp.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
func_exit();
+ unlock_kernel();
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1972,6 +1956,7 @@ static inline int sx_set_serial_info(struct specialix_port * port,
sx_change_speed(bp, port);
}
func_exit();
+ unlock_kernel();
return 0;
}
@@ -1984,12 +1969,8 @@ static inline int sx_get_serial_info(struct specialix_port * port,
func_enter();
- /*
- if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
- return -EFAULT;
- */
-
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.type = PORT_CIRRUS;
tmp.line = port - sx_port;
tmp.port = bp->base;
@@ -2000,6 +1981,7 @@ static inline int sx_get_serial_info(struct specialix_port * port,
tmp.closing_wait = port->closing_wait * HZ/100;
tmp.custom_divisor = port->custom_divisor;
tmp.xmit_fifo_size = CD186x_NFIFO;
+ unlock_kernel();
if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
func_exit();
return -EFAULT;
@@ -2045,23 +2027,6 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp,
sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
func_exit();
return 0;
- case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
- func_exit();
- return -EFAULT;
- }
- func_exit();
- return 0;
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp)) {
- func_exit();
- return -EFAULT;
- }
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- func_exit();
- return 0;
case TIOCGSERIAL:
func_exit();
return sx_get_serial_info(port, argp);
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 874aaa08e956..d17be10c5d21 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -875,6 +875,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
timeout = HZ;
tend = jiffies + timeout;
+ lock_kernel();
while (stl_datastate(portp)) {
if (signal_pending(current))
break;
@@ -882,6 +883,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
if (time_after_eq(jiffies, tend))
break;
}
+ unlock_kernel();
}
/*****************************************************************************/
@@ -1273,18 +1275,9 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
rc = 0;
+ lock_kernel();
+
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) argp);
- break;
- case TIOCSSOFTCAR:
- if (get_user(ival, (unsigned int __user *) arg))
- return -EFAULT;
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stl_getserial(portp, argp);
break;
@@ -1308,7 +1301,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
rc = -ENOIOCTLCMD;
break;
}
-
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index a6e1c9ba1217..b1a7a8cb65ea 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -384,11 +384,11 @@ static struct real_driver sx_real_driver = {
#define sx_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
-#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__FUNCTION__)
+#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__func__)
+#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__func__)
#define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
- __FUNCTION__, port->line)
+ __func__, port->line)
/*
* Firmware loader driver specific routines
@@ -970,7 +970,8 @@ static int sx_set_real_termios(void *ptr)
sx_write_channel_byte(port, hi_mask, 0x1f);
break;
default:
- printk(KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
+ printk(KERN_INFO "sx: Invalid wordsize: %u\n",
+ (unsigned int)CFLAG & CSIZE);
break;
}
@@ -997,7 +998,8 @@ static int sx_set_real_termios(void *ptr)
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
- port->gs.tty->termios->c_iflag, I_OTHER(port->gs.tty));
+ (unsigned int)port->gs.tty->termios->c_iflag,
+ I_OTHER(port->gs.tty));
/* Tell line discipline whether we will do output cooking.
* If OPOST is set and no other output flags are set then we can do output
@@ -1010,7 +1012,8 @@ static int sx_set_real_termios(void *ptr)
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
- port->gs.tty->termios->c_oflag, O_OTHER(port->gs.tty));
+ (unsigned int)port->gs.tty->termios->c_oflag,
+ O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
func_exit();
return 0;
@@ -1574,7 +1577,7 @@ static void sx_close(void *ptr)
sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
port->gs.count);
/*printk("%s SETTING port count to zero: %p count: %d\n",
- __FUNCTION__, port, port->gs.count);
+ __func__, port, port->gs.count);
port->gs.count = 0;*/
}
@@ -1844,6 +1847,7 @@ static void sx_break(struct tty_struct *tty, int flag)
int rv;
func_enter();
+ lock_kernel();
if (flag)
rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
@@ -1852,7 +1856,7 @@ static void sx_break(struct tty_struct *tty, int flag)
if (rv != 1)
printk(KERN_ERR "sx: couldn't send break (%x).\n",
read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
-
+ unlock_kernel();
func_exit();
}
@@ -1888,23 +1892,12 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
int rc;
struct sx_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
- int ival;
/* func_enter2(); */
rc = 0;
+ lock_kernel();
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *)argp);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) {
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- }
- break;
case TIOCGSERIAL:
rc = gs_getserial(&port->gs, argp);
break;
@@ -1915,6 +1908,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp,
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
/* func_exit(); */
return rc;
@@ -2549,7 +2543,7 @@ static int __devinit sx_eisa_probe(struct device *dev)
goto err_flag;
}
board->base2 =
- board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+ board->base = ioremap_nocache(board->hw_base, SI2_EISA_WINDOW_LEN);
if (!board->base) {
dev_err(dev, "can't remap memory\n");
goto err_reg;
@@ -2626,7 +2620,7 @@ static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
- rebase = ioremap(hwbase, 0x80);
+ rebase = ioremap_nocache(hwbase, 0x80);
t = readl(rebase + CNTRL_REG_OFFSET);
if (t != CNTRL_REG_GOODVALUE) {
printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
@@ -2770,7 +2764,7 @@ static int __init sx_init(void)
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_sx_reg;
board->flags &= ~SX_BOARD_TYPE;
@@ -2794,7 +2788,7 @@ err_sx_reg:
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_si_reg;
board->flags &= ~SX_BOARD_TYPE;
@@ -2817,7 +2811,7 @@ err_si_reg:
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_si1_reg;
board->flags &= ~SX_BOARD_TYPE;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index fadab1d9510f..ac5080df2565 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2026,34 +2026,35 @@ static void mgsl_change_params(struct mgsl_struct *info)
*
* Return Value: None
*/
-static void mgsl_put_char(struct tty_struct *tty, unsigned char ch)
+static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+ struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
+ int ret = 0;
- if ( debug_level >= DEBUG_LEVEL_INFO ) {
- printk( "%s(%d):mgsl_put_char(%d) on %s\n",
- __FILE__,__LINE__,ch,info->device_name);
+ if (debug_level >= DEBUG_LEVEL_INFO) {
+ printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n",
+ __FILE__, __LINE__, ch, info->device_name);
}
if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char"))
- return;
+ return 0;
if (!tty || !info->xmit_buf)
- return;
+ return 0;
- spin_lock_irqsave(&info->irq_spinlock,flags);
-
- if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
+ spin_lock_irqsave(&info->irq_spinlock, flags);
+ if ((info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active) {
if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= SERIAL_XMIT_SIZE-1;
info->xmit_cnt++;
+ ret = 1;
}
}
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ spin_unlock_irqrestore(&info->irq_spinlock, flags);
+ return ret;
} /* end of mgsl_put_char() */
@@ -2942,6 +2943,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+ int ret;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
@@ -2956,7 +2958,10 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
return -EIO;
}
- return mgsl_ioctl_common(info, cmd, arg);
+ lock_kernel();
+ ret = mgsl_ioctl_common(info, cmd, arg);
+ unlock_kernel();
+ return ret;
}
static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
@@ -3153,8 +3158,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
if (info->flags & ASYNC_INITIALIZED)
mgsl_wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mgsl_flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -3217,7 +3221,8 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
* interval should also be less than the timeout.
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
-
+
+ lock_kernel();
if ( info->params.data_rate ) {
char_time = info->timeout/(32 * 5);
if (!char_time)
@@ -3247,6 +3252,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
}
+ unlock_kernel();
exit:
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4144,7 +4150,8 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
}
info->lcr_mem_requested = true;
- info->memory_base = ioremap(info->phys_memory_base,0x40000);
+ info->memory_base = ioremap_nocache(info->phys_memory_base,
+ 0x40000);
if (!info->memory_base) {
printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -4157,12 +4164,14 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
goto errout;
}
- info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
+ info->lcr_base = ioremap_nocache(info->phys_lcr_base,
+ PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
goto errout;
}
+ info->lcr_base += info->lcr_offset;
} else {
/* claim DMA channel */
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index f3d8d72e5ea4..55c1653be00c 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -151,7 +151,7 @@ static void hangup(struct tty_struct *tty);
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void put_char(struct tty_struct *tty, unsigned char ch);
+static int put_char(struct tty_struct *tty, unsigned char ch);
static void send_xchar(struct tty_struct *tty, char ch);
static void wait_until_sent(struct tty_struct *tty, int timeout);
static int write_room(struct tty_struct *tty);
@@ -771,8 +771,7 @@ static void close(struct tty_struct *tty, struct file *filp)
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(info);
@@ -913,20 +912,24 @@ cleanup:
return ret;
}
-static void put_char(struct tty_struct *tty, unsigned char ch)
+static int put_char(struct tty_struct *tty, unsigned char ch)
{
struct slgt_info *info = tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (sanity_check(info, tty->name, "put_char"))
- return;
+ return 0;
DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active && (info->tx_count < info->max_frame_size))
+ if (!info->tx_active && (info->tx_count < info->max_frame_size)) {
info->tx_buf[info->tx_count++] = ch;
+ ret = 1;
+ }
spin_unlock_irqrestore(&info->lock,flags);
+ return ret;
}
static void send_xchar(struct tty_struct *tty, char ch)
@@ -967,6 +970,8 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
+ lock_kernel();
+
if (info->params.data_rate) {
char_time = info->timeout/(32 * 5);
if (!char_time)
@@ -984,6 +989,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
+ unlock_kernel();
exit:
DBGINFO(("%s wait_until_sent exit\n", info->device_name));
@@ -1097,6 +1103,7 @@ static int ioctl(struct tty_struct *tty, struct file *file,
struct serial_icounter_struct __user *p_cuser; /* user space */
unsigned long flags;
void __user *argp = (void __user *)arg;
+ int ret;
if (sanity_check(info, tty->name, "ioctl"))
return -ENODEV;
@@ -1108,37 +1115,54 @@ static int ioctl(struct tty_struct *tty, struct file *file,
return -EIO;
}
+ lock_kernel();
+
switch (cmd) {
case MGSL_IOCGPARAMS:
- return get_params(info, argp);
+ ret = get_params(info, argp);
+ break;
case MGSL_IOCSPARAMS:
- return set_params(info, argp);
+ ret = set_params(info, argp);
+ break;
case MGSL_IOCGTXIDLE:
- return get_txidle(info, argp);
+ ret = get_txidle(info, argp);
+ break;
case MGSL_IOCSTXIDLE:
- return set_txidle(info, (int)arg);
+ ret = set_txidle(info, (int)arg);
+ break;
case MGSL_IOCTXENABLE:
- return tx_enable(info, (int)arg);
+ ret = tx_enable(info, (int)arg);
+ break;
case MGSL_IOCRXENABLE:
- return rx_enable(info, (int)arg);
+ ret = rx_enable(info, (int)arg);
+ break;
case MGSL_IOCTXABORT:
- return tx_abort(info);
+ ret = tx_abort(info);
+ break;
case MGSL_IOCGSTATS:
- return get_stats(info, argp);
+ ret = get_stats(info, argp);
+ break;
case MGSL_IOCWAITEVENT:
- return wait_mgsl_event(info, argp);
+ ret = wait_mgsl_event(info, argp);
+ break;
case TIOCMIWAIT:
- return modem_input_wait(info,(int)arg);
+ ret = modem_input_wait(info,(int)arg);
+ break;
case MGSL_IOCGIF:
- return get_interface(info, argp);
+ ret = get_interface(info, argp);
+ break;
case MGSL_IOCSIF:
- return set_interface(info,(int)arg);
+ ret = set_interface(info,(int)arg);
+ break;
case MGSL_IOCSGPIO:
- return set_gpio(info, argp);
+ ret = set_gpio(info, argp);
+ break;
case MGSL_IOCGGPIO:
- return get_gpio(info, argp);
+ ret = get_gpio(info, argp);
+ break;
case MGSL_IOCWAITGPIO:
- return wait_gpio(info, argp);
+ ret = wait_gpio(info, argp);
+ break;
case TIOCGICOUNT:
spin_lock_irqsave(&info->lock,flags);
cnow = info->icount;
@@ -1155,12 +1179,14 @@ static int ioctl(struct tty_struct *tty, struct file *file,
put_user(cnow.parity, &p_cuser->parity) ||
put_user(cnow.brk, &p_cuser->brk) ||
put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ ret = 0;
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
- return 0;
+ unlock_kernel();
+ return ret;
}
/*
@@ -3324,7 +3350,7 @@ static int claim_resources(struct slgt_info *info)
else
info->reg_addr_requested = true;
- info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE);
+ info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE);
if (!info->reg_addr) {
DBGERR(("%s cant map device registers, addr=%08X\n",
info->device_name, info->phys_reg_addr));
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index e98c3e6f8216..bec54866e0bb 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -519,7 +519,7 @@ static void hangup(struct tty_struct *tty);
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void put_char(struct tty_struct *tty, unsigned char ch);
+static int put_char(struct tty_struct *tty, unsigned char ch);
static void send_xchar(struct tty_struct *tty, char ch);
static void wait_until_sent(struct tty_struct *tty, int timeout);
static int write_room(struct tty_struct *tty);
@@ -862,8 +862,7 @@ static void close(struct tty_struct *tty, struct file *filp)
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -1046,10 +1045,11 @@ cleanup:
/* Add a character to the transmit buffer.
*/
-static void put_char(struct tty_struct *tty, unsigned char ch)
+static int put_char(struct tty_struct *tty, unsigned char ch)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
unsigned long flags;
+ int ret = 0;
if ( debug_level >= DEBUG_LEVEL_INFO ) {
printk( "%s(%d):%s put_char(%d)\n",
@@ -1057,10 +1057,10 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
}
if (sanity_check(info, tty->name, "put_char"))
- return;
+ return 0;
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
@@ -1072,10 +1072,12 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
if (info->tx_put >= info->max_frame_size)
info->tx_put -= info->max_frame_size;
info->tx_count++;
+ ret = 1;
}
}
spin_unlock_irqrestore(&info->lock,flags);
+ return ret;
}
/* Send a high-priority XON/XOFF character
@@ -1119,6 +1121,8 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
if (sanity_check(info, tty->name, "wait_until_sent"))
return;
+ lock_kernel();
+
if (!(info->flags & ASYNC_INITIALIZED))
goto exit;
@@ -1161,6 +1165,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
}
exit:
+ unlock_kernel();
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s wait_until_sent() exit\n",
__FILE__,__LINE__, info->device_name );
@@ -1176,6 +1181,7 @@ static int write_room(struct tty_struct *tty)
if (sanity_check(info, tty->name, "write_room"))
return 0;
+ lock_kernel();
if (info->params.mode == MGSL_MODE_HDLC) {
ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
} else {
@@ -1183,6 +1189,7 @@ static int write_room(struct tty_struct *tty)
if (ret < 0)
ret = 0;
}
+ unlock_kernel();
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s write_room()=%d\n",
@@ -1303,7 +1310,7 @@ static void tx_release(struct tty_struct *tty)
*
* Return Value: 0 if success, otherwise error code
*/
-static int ioctl(struct tty_struct *tty, struct file *file,
+static int do_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
@@ -1393,6 +1400,16 @@ static int ioctl(struct tty_struct *tty, struct file *file,
return 0;
}
+static int ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ lock_kernel();
+ ret = do_ioctl(tty, file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
/*
* /proc fs routines....
*/
@@ -3626,7 +3643,8 @@ static int claim_resources(SLMP_INFO *info)
else
info->sca_statctrl_requested = true;
- info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE);
+ info->memory_base = ioremap_nocache(info->phys_memory_base,
+ SCA_MEM_SIZE);
if (!info->memory_base) {
printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -3634,7 +3652,7 @@ static int claim_resources(SLMP_INFO *info)
goto errout;
}
- info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE);
+ info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
@@ -3643,7 +3661,7 @@ static int claim_resources(SLMP_INFO *info)
}
info->lcr_base += info->lcr_offset;
- info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE);
+ info->sca_base = ioremap_nocache(info->phys_sca_base, PAGE_SIZE);
if (!info->sca_base) {
printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base );
@@ -3652,7 +3670,8 @@ static int claim_resources(SLMP_INFO *info)
}
info->sca_base += info->sca_offset;
- info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE);
+ info->statctrl_base = ioremap_nocache(info->phys_statctrl_base,
+ PAGE_SIZE);
if (!info->statctrl_base) {
printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1ade193c9128..9e9bad8bdcf4 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -196,6 +196,48 @@ static struct sysrq_key_op sysrq_showlocks_op = {
#define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
#endif
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(show_lock);
+
+static void showacpu(void *dummy)
+{
+ unsigned long flags;
+
+ /* Idle CPUs have no interesting backtrace. */
+ if (idle_cpu(smp_processor_id()))
+ return;
+
+ spin_lock_irqsave(&show_lock, flags);
+ printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+ show_stack(NULL, NULL);
+ spin_unlock_irqrestore(&show_lock, flags);
+}
+
+static void sysrq_showregs_othercpus(struct work_struct *dummy)
+{
+ smp_call_function(showacpu, NULL, 0, 0);
+}
+
+static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
+
+static void sysrq_handle_showallcpus(int key, struct tty_struct *tty)
+{
+ struct pt_regs *regs = get_irq_regs();
+ if (regs) {
+ printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+ show_regs(regs);
+ }
+ schedule_work(&sysrq_showallcpus);
+}
+
+static struct sysrq_key_op sysrq_showallcpus_op = {
+ .handler = sysrq_handle_showallcpus,
+ .help_msg = "aLlcpus",
+ .action_msg = "Show backtrace of all active CPUs",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
static void sysrq_handle_showregs(int key, struct tty_struct *tty)
{
struct pt_regs *regs = get_irq_regs();
@@ -340,7 +382,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
&sysrq_kill_op, /* i */
NULL, /* j */
&sysrq_SAK_op, /* k */
+#ifdef CONFIG_SMP
+ &sysrq_showallcpus_op, /* l */
+#else
NULL, /* l */
+#endif
&sysrq_showmem_op, /* m */
&sysrq_unrt_op, /* n */
/* o: This will often be registered as 'Off' at init time */
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index ce5ebe3b168f..663cd15d7c78 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -426,7 +426,7 @@ static int tosh_probe(void)
int i,major,minor,day,year,month,flag;
unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 };
SMMRegisters regs;
- void __iomem *bios = ioremap(0xf0000, 0x10000);
+ void __iomem *bios = ioremap_cache(0xf0000, 0x10000);
if (!bios)
return -ENOMEM;
@@ -520,12 +520,11 @@ static int __init toshiba_init(void)
{
struct proc_dir_entry *pde;
- pde = create_proc_entry("toshiba", 0, NULL);
+ pde = proc_create("toshiba", 0, NULL, &proc_toshiba_fops);
if (!pde) {
misc_deregister(&tosh_device);
return -ENOMEM;
}
- pde->proc_fops = &proc_toshiba_fops;
}
#endif
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 8f3f7620f95a..3738cfa209ff 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -23,7 +23,7 @@ if TCG_TPM
config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface"
- depends on PNPACPI
+ depends on PNP
---help---
If you have a TPM security chip that is compliant with the
TCG TIS 1.2 TPM specification say Yes and it will be accessible
@@ -32,7 +32,6 @@ config TCG_TIS
config TCG_NSC
tristate "National Semiconductor TPM Interface"
- depends on PNPACPI
---help---
If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
@@ -48,7 +47,7 @@ config TCG_ATMEL
config TCG_INFINEON
tristate "Infineon Technologies TPM Interface"
- depends on PNPACPI
+ depends on PNP
---help---
If you have a TPM security chip from Infineon Technologies
(either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 6313326bc41f..ab18c1e7b115 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -264,7 +264,7 @@ static const struct tpm_vendor_specific tpm_nsc = {
static struct platform_device *pdev = NULL;
-static void __devexit tpm_nsc_remove(struct device *dev)
+static void tpm_nsc_remove(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if ( chip ) {
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 7722466e052f..3582f43345a8 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -11,6 +11,7 @@
#include <linux/audit.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/tty.h>
struct tty_audit_buf {
@@ -92,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
- audit_log_n_untrustedstring(ab, buf->valid, buf->data);
+ audit_log_n_untrustedstring(ab, buf->data, buf->valid);
audit_log_end(ab);
}
buf->valid = 0;
@@ -151,14 +152,9 @@ void tty_audit_fork(struct signal_struct *sig)
/**
* tty_audit_push_task - Flush task's pending audit data
*/
-void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
+void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
{
struct tty_audit_buf *buf;
- /* FIXME I think this is correct. Check against netlink once that is
- * I really need to read this code more closely. But that's for
- * another patch.
- */
- unsigned int sessionid = audit_get_sessionid(tsk);
spin_lock_irq(&tsk->sighand->siglock);
buf = tsk->signal->tty_audit_buf;
@@ -238,6 +234,10 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
if (unlikely(size == 0))
return;
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY
+ && tty->driver->subtype == PTY_TYPE_MASTER)
+ return;
+
buf = tty_audit_buf_get(tty);
if (!buf)
return;
@@ -300,53 +300,3 @@ void tty_audit_push(struct tty_struct *tty)
tty_audit_buf_put(buf);
}
}
-
-/**
- * tty_audit_opening - A TTY is being opened.
- *
- * As a special hack, tasks that close all their TTYs and open new ones
- * are assumed to be system daemons (e.g. getty) and auditing is
- * automatically disabled for them.
- */
-void tty_audit_opening(void)
-{
- int disable;
-
- disable = 1;
- spin_lock_irq(&current->sighand->siglock);
- if (current->signal->audit_tty == 0)
- disable = 0;
- spin_unlock_irq(&current->sighand->siglock);
- if (!disable)
- return;
-
- task_lock(current);
- if (current->files) {
- struct fdtable *fdt;
- unsigned i;
-
- /*
- * We don't take a ref to the file, so we must hold ->file_lock
- * instead.
- */
- spin_lock(&current->files->file_lock);
- fdt = files_fdtable(current->files);
- for (i = 0; i < fdt->max_fds; i++) {
- struct file *filp;
-
- filp = fcheck_files(current->files, i);
- if (filp && is_tty(filp)) {
- disable = 0;
- break;
- }
- }
- spin_unlock(&current->files->file_lock);
- }
- task_unlock(current);
- if (!disable)
- return;
-
- spin_lock_irq(&current->sighand->siglock);
- current->signal->audit_tty = 0;
- spin_unlock_irq(&current->sighand->siglock);
-}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 98b65a230994..e94bee032314 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -78,6 +78,7 @@
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
@@ -91,7 +92,6 @@
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
-#include <linux/idr.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -137,9 +137,6 @@ EXPORT_SYMBOL(tty_mutex);
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
-extern int pty_limit; /* Config limit on Unix98 ptys */
-static DEFINE_IDR(allocated_ptys);
-static DEFINE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
@@ -152,8 +149,7 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
-int tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
@@ -1109,8 +1105,8 @@ restart:
a reference to the old ldisc. If we ended up flipping back
to the existing ldisc we have two references to it */
- if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc)
- tty->driver->set_ldisc(tty);
+ if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc)
+ tty->ops->set_ldisc(tty);
tty_ldisc_put(o_ldisc.num);
@@ -1182,9 +1178,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (*str == '\0')
str = NULL;
- if (tty_line >= 0 && tty_line <= p->num && p->poll_init &&
- !p->poll_init(p, tty_line, str)) {
-
+ if (tty_line >= 0 && tty_line <= p->num && p->ops &&
+ p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
res = p;
*line = tty_line;
break;
@@ -1205,26 +1200,40 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
* not in the foreground, send a SIGTTOU. If the signal is blocked or
* ignored, go ahead and perform the operation. (POSIX 7.2)
*
- * Locking: none
+ * Locking: ctrl_lock
*/
int tty_check_change(struct tty_struct *tty)
{
+ unsigned long flags;
+ int ret = 0;
+
if (current->signal->tty != tty)
return 0;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+
if (!tty->pgrp) {
printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
- return 0;
+ goto out_unlock;
}
if (task_pgrp(current) == tty->pgrp)
- return 0;
+ goto out_unlock;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (is_ignored(SIGTTOU))
- return 0;
- if (is_current_pgrp_orphaned())
- return -EIO;
+ goto out;
+ if (is_current_pgrp_orphaned()) {
+ ret = -EIO;
+ goto out;
+ }
kill_pgrp(task_pgrp(current), SIGTTOU, 1);
set_thread_flag(TIF_SIGPENDING);
- return -ERESTARTSYS;
+ ret = -ERESTARTSYS;
+out:
+ return ret;
+out_unlock:
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ return ret;
}
EXPORT_SYMBOL(tty_check_change);
@@ -1247,8 +1256,8 @@ static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
}
-static int hung_up_tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
@@ -1264,7 +1273,7 @@ static const struct file_operations tty_fops = {
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
@@ -1277,7 +1286,7 @@ static const struct file_operations ptmx_fops = {
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = ptmx_open,
.release = tty_release,
@@ -1290,7 +1299,7 @@ static const struct file_operations console_fops = {
.read = tty_read,
.write = redirected_tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
@@ -1302,7 +1311,7 @@ static const struct file_operations hung_up_tty_fops = {
.read = hung_up_tty_read,
.write = hung_up_tty_write,
.poll = hung_up_tty_poll,
- .ioctl = hung_up_tty_ioctl,
+ .unlocked_ioctl = hung_up_tty_ioctl,
.compat_ioctl = hung_up_tty_compat_ioctl,
.release = tty_release,
};
@@ -1404,6 +1413,7 @@ static void do_tty_hangup(struct work_struct *work)
struct task_struct *p;
struct tty_ldisc *ld;
int closecount = 0, n;
+ unsigned long flags;
if (!tty)
return;
@@ -1441,8 +1451,7 @@ static void do_tty_hangup(struct work_struct *work)
/* We may have no line discipline at this point */
if (ld->flush_buffer)
ld->flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->write_wakeup)
ld->write_wakeup(tty);
@@ -1480,19 +1489,24 @@ 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);
put_pid(p->signal->tty_old_pgrp); /* A noop */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp)
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
spin_unlock_irq(&p->sighand->siglock);
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->flags = 0;
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
/*
* If one of the devices matches a console pointer, we
* cannot just call hangup() because that will cause
@@ -1500,11 +1514,11 @@ static void do_tty_hangup(struct work_struct *work)
* So we just call close() the right number of times.
*/
if (cons_filp) {
- if (tty->driver->close)
+ if (tty->ops->close)
for (n = 0; n < closecount; n++)
- tty->driver->close(tty, cons_filp);
- } else if (tty->driver->hangup)
- (tty->driver->hangup)(tty);
+ tty->ops->close(tty, cons_filp);
+ } else if (tty->ops->hangup)
+ (tty->ops->hangup)(tty);
/*
* We don't want to have driver/ldisc interactions beyond
* the ones we did here. The driver layer expects no
@@ -1626,16 +1640,17 @@ void disassociate_ctty(int on_exit)
struct tty_struct *tty;
struct pid *tty_pgrp = NULL;
- lock_kernel();
mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
tty_pgrp = get_pid(tty->pgrp);
mutex_unlock(&tty_mutex);
+ lock_kernel();
/* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
+ unlock_kernel();
} else if (on_exit) {
struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock);
@@ -1648,7 +1663,6 @@ void disassociate_ctty(int on_exit)
put_pid(old_pgrp);
}
mutex_unlock(&tty_mutex);
- unlock_kernel();
return;
}
if (tty_pgrp) {
@@ -1667,10 +1681,13 @@ void disassociate_ctty(int on_exit)
/* It is possible that do_tty_hangup has free'd this tty */
tty = get_current_tty();
if (tty) {
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
} else {
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1683,7 +1700,6 @@ void disassociate_ctty(int on_exit)
read_lock(&tasklist_lock);
session_clear_tty(task_session(current));
read_unlock(&tasklist_lock);
- unlock_kernel();
}
/**
@@ -1693,8 +1709,10 @@ void disassociate_ctty(int on_exit)
void no_tty(void)
{
struct task_struct *tsk = current;
+ lock_kernel();
if (tsk->signal->leader)
disassociate_ctty(0);
+ unlock_kernel();
proc_clear_tty(tsk);
}
@@ -1714,21 +1732,26 @@ void no_tty(void)
* but not always.
*
* Locking:
- * Broken. Relies on BKL which is unsafe here.
+ * Uses the tty control lock internally
*/
void stop_tty(struct tty_struct *tty)
{
- if (tty->stopped)
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (tty->stopped) {
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return;
+ }
tty->stopped = 1;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_START;
tty->ctrl_status |= TIOCPKT_STOP;
wake_up_interruptible(&tty->link->read_wait);
}
- if (tty->driver->stop)
- (tty->driver->stop)(tty);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->ops->stop)
+ (tty->ops->stop)(tty);
}
EXPORT_SYMBOL(stop_tty);
@@ -1743,21 +1766,26 @@ EXPORT_SYMBOL(stop_tty);
* driver start method is invoked and the line discipline woken.
*
* Locking:
- * Broken. Relies on BKL which is unsafe here.
+ * ctrl_lock
*/
void start_tty(struct tty_struct *tty)
{
- if (!tty->stopped || tty->flow_stopped)
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (!tty->stopped || tty->flow_stopped) {
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return;
+ }
tty->stopped = 0;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_STOP;
tty->ctrl_status |= TIOCPKT_START;
wake_up_interruptible(&tty->link->read_wait);
}
- if (tty->driver->start)
- (tty->driver->start)(tty);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->ops->start)
+ (tty->ops->start)(tty);
/* If we have a running line discipline it may need kicking */
tty_wakeup(tty);
}
@@ -1775,10 +1803,8 @@ EXPORT_SYMBOL(start_tty);
* for hung up devices before calling the line discipline method.
*
* Locking:
- * Locks the line discipline internally while needed
- * For historical reasons the line discipline read method is
- * invoked under the BKL. This will go away in time so do not rely on it
- * in new code. Multiple read calls may be outstanding in parallel.
+ * Locks the line discipline internally while needed. Multiple
+ * read calls may be outstanding in parallel.
*/
static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
@@ -1799,13 +1825,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
- lock_kernel();
if (ld->read)
i = (ld->read)(tty, file, buf, count);
else
i = -EIO;
tty_ldisc_deref(ld);
- unlock_kernel();
if (i > 0)
inode->i_atime = current_fs_time(inode->i_sb);
return i;
@@ -1893,9 +1917,7 @@ static inline ssize_t do_tty_write(
ret = -EFAULT;
if (copy_from_user(tty->write_buf, buf, size))
break;
- lock_kernel();
ret = write(tty, file, tty->write_buf, size);
- unlock_kernel();
if (ret <= 0)
break;
written += ret;
@@ -1948,10 +1970,13 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO;
- if (!tty || !tty->driver->write ||
+ if (!tty || !tty->ops->write ||
(test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
-
+ /* Short term debug to catch buggy drivers */
+ if (tty->ops->write_room == NULL)
+ printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
+ tty->driver->name);
ld = tty_ldisc_ref_wait(tty);
if (!ld->write)
ret = -EIO;
@@ -2098,6 +2123,7 @@ static int init_dev(struct tty_driver *driver, int idx,
goto fail_no_mem;
initialize_tty_struct(tty);
tty->driver = driver;
+ tty->ops = driver->ops;
tty->index = idx;
tty_line_name(driver, idx, tty->name);
@@ -2128,6 +2154,7 @@ static int init_dev(struct tty_driver *driver, int idx,
goto free_mem_out;
initialize_tty_struct(o_tty);
o_tty->driver = driver->other;
+ o_tty->ops = driver->ops;
o_tty->index = idx;
tty_line_name(driver->other, idx, o_tty->name);
@@ -2432,8 +2459,8 @@ static void release_dev(struct file *filp)
}
}
#endif
- if (tty->driver->close)
- tty->driver->close(tty, filp);
+ if (tty->ops->close)
+ tty->ops->close(tty, filp);
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
@@ -2612,15 +2639,9 @@ static void release_dev(struct file *filp)
*/
release_tty(tty, idx);
-#ifdef CONFIG_UNIX98_PTYS
/* Make this pty number available for reallocation */
- if (devpts) {
- mutex_lock(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, idx);
- mutex_unlock(&allocated_ptys_lock);
- }
-#endif
-
+ if (devpts)
+ devpts_kill_index(idx);
}
/**
@@ -2716,8 +2737,8 @@ got_driver:
printk(KERN_DEBUG "opening %s...", tty->name);
#endif
if (!retval) {
- if (tty->driver->open)
- retval = tty->driver->open(tty, filp);
+ if (tty->ops->open)
+ retval = tty->ops->open(tty, filp);
else
retval = -ENODEV;
}
@@ -2755,7 +2776,6 @@ got_driver:
__proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
mutex_unlock(&tty_mutex);
- tty_audit_opening();
return 0;
}
@@ -2777,29 +2797,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
struct tty_struct *tty;
int retval;
int index;
- int idr_ret;
nonseekable_open(inode, filp);
/* find a device that is not in use. */
- mutex_lock(&allocated_ptys_lock);
- if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
- mutex_unlock(&allocated_ptys_lock);
- return -ENOMEM;
- }
- idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
- if (idr_ret < 0) {
- mutex_unlock(&allocated_ptys_lock);
- if (idr_ret == -EAGAIN)
- return -ENOMEM;
- return -EIO;
- }
- if (index >= pty_limit) {
- idr_remove(&allocated_ptys, index);
- mutex_unlock(&allocated_ptys_lock);
- return -EIO;
- }
- mutex_unlock(&allocated_ptys_lock);
+ index = devpts_new_index();
+ if (index < 0)
+ return index;
mutex_lock(&tty_mutex);
retval = init_dev(ptm_driver, index, &tty);
@@ -2812,23 +2816,19 @@ static int ptmx_open(struct inode *inode, struct file *filp)
filp->private_data = tty;
file_move(filp, &tty->tty_files);
- retval = -ENOMEM;
- if (devpts_pty_new(tty->link))
+ retval = devpts_pty_new(tty->link);
+ if (retval)
goto out1;
- check_tty_count(tty, "tty_open");
- retval = ptm_driver->open(tty, filp);
- if (!retval) {
- tty_audit_opening();
+ check_tty_count(tty, "ptmx_open");
+ retval = ptm_driver->ops->open(tty, filp);
+ if (!retval)
return 0;
- }
out1:
release_dev(filp);
return retval;
out:
- mutex_lock(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, index);
- mutex_unlock(&allocated_ptys_lock);
+ devpts_kill_index(index);
return retval;
}
#endif
@@ -2885,6 +2885,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
static int tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty;
+ unsigned long flags;
int retval;
tty = (struct tty_struct *)filp->private_data;
@@ -2900,6 +2901,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp) {
pid = tty->pgrp;
type = PIDTYPE_PGID;
@@ -2907,6 +2909,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
pid = task_pid(current);
type = PIDTYPE_PID;
}
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0);
if (retval)
return retval;
@@ -2992,6 +2995,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize __user *arg)
{
struct winsize tmp_ws;
+ struct pid *pgrp, *rpgrp;
+ unsigned long flags;
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
@@ -3009,10 +3014,21 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
}
}
#endif
- 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);
+ /* Get the PID values and reference them so we can
+ avoid holding the tty ctrl lock while sending signals */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ pgrp = get_pid(tty->pgrp);
+ rpgrp = get_pid(real_tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ if (pgrp)
+ kill_pgrp(pgrp, SIGWINCH, 1);
+ if (rpgrp != pgrp && rpgrp)
+ kill_pgrp(rpgrp, SIGWINCH, 1);
+
+ put_pid(pgrp);
+ put_pid(rpgrp);
+
tty->winsize = tmp_ws;
real_tty->winsize = tmp_ws;
done:
@@ -3073,10 +3089,13 @@ static int fionbio(struct file *file, int __user *p)
if (get_user(nonblock, p))
return -EFAULT;
+ /* file->f_flags is still BKL protected in the fs layer - vomit */
+ lock_kernel();
if (nonblock)
file->f_flags |= O_NONBLOCK;
else
file->f_flags &= ~O_NONBLOCK;
+ unlock_kernel();
return 0;
}
@@ -3134,6 +3153,27 @@ unlock:
}
/**
+ * tty_get_pgrp - return a ref counted pgrp pid
+ * @tty: tty to read
+ *
+ * Returns a refcounted instance of the pid struct for the process
+ * group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+ unsigned long flags;
+ struct pid *pgrp;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ pgrp = get_pid(tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
+/**
* tiocgpgrp - get process group
* @tty: tty passed by user
* @real_tty: tty side of the tty pased by the user if a pty else the tty
@@ -3147,13 +3187,18 @@ unlock:
static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
+ struct pid *pid;
+ int ret;
/*
* (tty == real_tty) is a cheap way of
* testing if the tty is NOT a master pty.
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- return put_user(pid_vnr(real_tty->pgrp), p);
+ pid = tty_get_pgrp(real_tty);
+ ret = put_user(pid_vnr(pid), p);
+ put_pid(pid);
+ return ret;
}
/**
@@ -3165,7 +3210,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
* Set the process group of the tty to the session passed. Only
* permitted where the tty session is our session.
*
- * Locking: None
+ * Locking: RCU, ctrl lock
*/
static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3173,6 +3218,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
struct pid *pgrp;
pid_t pgrp_nr;
int retval = tty_check_change(real_tty);
+ unsigned long flags;
if (retval == -EIO)
return -ENOTTY;
@@ -3195,8 +3241,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(real_tty->pgrp);
real_tty->pgrp = get_pid(pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
out_unlock:
rcu_read_unlock();
return retval;
@@ -3240,10 +3288,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
int ldisc;
+ int ret;
if (get_user(ldisc, p))
return -EFAULT;
- return tty_set_ldisc(tty, ldisc);
+
+ lock_kernel();
+ ret = tty_set_ldisc(tty, ldisc);
+ unlock_kernel();
+
+ return ret;
}
/**
@@ -3263,18 +3317,18 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
{
if (tty_write_lock(tty, 0) < 0)
return -EINTR;
- tty->driver->break_ctl(tty, -1);
+ tty->ops->break_ctl(tty, -1);
if (!signal_pending(current))
msleep_interruptible(duration);
- tty->driver->break_ctl(tty, 0);
+ tty->ops->break_ctl(tty, 0);
tty_write_unlock(tty);
- if (signal_pending(current))
+ if (!signal_pending(current))
return -EINTR;
return 0;
}
/**
- * tiocmget - get modem status
+ * tty_tiocmget - get modem status
* @tty: tty device
* @file: user file pointer
* @p: pointer to result
@@ -3289,8 +3343,8 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
{
int retval = -EINVAL;
- if (tty->driver->tiocmget) {
- retval = tty->driver->tiocmget(tty, file);
+ if (tty->ops->tiocmget) {
+ retval = tty->ops->tiocmget(tty, file);
if (retval >= 0)
retval = put_user(retval, p);
@@ -3299,7 +3353,7 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
}
/**
- * tiocmset - set modem status
+ * tty_tiocmset - set modem status
* @tty: tty device
* @file: user file pointer
* @cmd: command - clear bits, set bits or set all
@@ -3316,7 +3370,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
{
int retval = -EINVAL;
- if (tty->driver->tiocmset) {
+ if (tty->ops->tiocmset) {
unsigned int set, clear, val;
retval = get_user(val, p);
@@ -3340,7 +3394,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
- retval = tty->driver->tiocmset(tty, file, set, clear);
+ retval = tty->ops->tiocmset(tty, file, set, clear);
}
return retval;
}
@@ -3348,20 +3402,18 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
/*
* Split this up, as gcc can choke on it otherwise..
*/
-int tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct tty_struct *tty, *real_tty;
void __user *p = (void __user *)arg;
int retval;
struct tty_ldisc *ld;
+ struct inode *inode = file->f_dentry->d_inode;
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- /* CHECKME: is this safe as one end closes ? */
-
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -3370,21 +3422,28 @@ int tty_ioctl(struct inode *inode, struct file *file,
/*
* Break handling by driver
*/
- if (!tty->driver->break_ctl) {
+
+ retval = -EINVAL;
+
+ if (!tty->ops->break_ctl) {
switch (cmd) {
case TIOCSBRK:
case TIOCCBRK:
- if (tty->driver->ioctl)
- return tty->driver->ioctl(tty, file, cmd, arg);
- return -EINVAL;
+ if (tty->ops->ioctl)
+ retval = tty->ops->ioctl(tty, file, cmd, arg);
+ if (retval != -EINVAL && retval != -ENOIOCTLCMD)
+ printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
+ return retval;
/* These two ioctl's always return success; even if */
/* the driver doesn't support them. */
case TCSBRK:
case TCSBRKP:
- if (!tty->driver->ioctl)
+ if (!tty->ops->ioctl)
return 0;
- retval = tty->driver->ioctl(tty, file, cmd, arg);
+ retval = tty->ops->ioctl(tty, file, cmd, arg);
+ if (retval != -EINVAL && retval != -ENOIOCTLCMD)
+ printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
if (retval == -ENOIOCTLCMD)
retval = 0;
return retval;
@@ -3442,7 +3501,6 @@ int tty_ioctl(struct inode *inode, struct file *file,
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
- /* FIXME: check this is ok */
return put_user(tty->ldisc.num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
@@ -3454,11 +3512,13 @@ int tty_ioctl(struct inode *inode, struct file *file,
* Break handling
*/
case TIOCSBRK: /* Turn break on, unconditionally */
- tty->driver->break_ctl(tty, -1);
+ if (tty->ops->break_ctl)
+ tty->ops->break_ctl(tty, -1);
return 0;
case TIOCCBRK: /* Turn break off, unconditionally */
- tty->driver->break_ctl(tty, 0);
+ if (tty->ops->break_ctl)
+ tty->ops->break_ctl(tty, 0);
return 0;
case TCSBRK: /* SVID version: non-zero arg --> no break */
/* non-zero arg means wait for all output data
@@ -3487,8 +3547,8 @@ int tty_ioctl(struct inode *inode, struct file *file,
}
break;
}
- if (tty->driver->ioctl) {
- retval = (tty->driver->ioctl)(tty, file, cmd, arg);
+ if (tty->ops->ioctl) {
+ retval = (tty->ops->ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@@ -3515,8 +3575,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- if (tty->driver->compat_ioctl) {
- retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+ if (tty->ops->compat_ioctl) {
+ retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@@ -3566,8 +3626,7 @@ void __do_SAK(struct tty_struct *tty)
tty_ldisc_flush(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
read_lock(&tasklist_lock);
/* Kill the entire session */
@@ -3773,19 +3832,32 @@ static void initialize_tty_struct(struct tty_struct *tty)
mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->read_lock);
+ spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
}
-/*
- * The default put_char routine if the driver did not define one.
+/**
+ * tty_put_char - write one character to a tty
+ * @tty: tty
+ * @ch: character
+ *
+ * Write one byte to the tty using the provided put_char method
+ * if present. Returns the number of characters successfully output.
+ *
+ * Note: the specific put_char operation in the driver layer may go
+ * away soon. Don't call it directly, use this method
*/
-static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
+int tty_put_char(struct tty_struct *tty, unsigned char ch)
{
- tty->driver->write(tty, &ch, 1);
+ if (tty->ops->put_char)
+ return tty->ops->put_char(tty, ch);
+ return tty->ops->write(tty, &ch, 1);
}
+EXPORT_SYMBOL_GPL(tty_put_char);
+
static struct class *tty_class;
/**
@@ -3868,37 +3940,8 @@ void put_tty_driver(struct tty_driver *driver)
void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op)
{
- driver->open = op->open;
- driver->close = op->close;
- driver->write = op->write;
- driver->put_char = op->put_char;
- driver->flush_chars = op->flush_chars;
- driver->write_room = op->write_room;
- driver->chars_in_buffer = op->chars_in_buffer;
- driver->ioctl = op->ioctl;
- driver->compat_ioctl = op->compat_ioctl;
- driver->set_termios = op->set_termios;
- driver->throttle = op->throttle;
- driver->unthrottle = op->unthrottle;
- driver->stop = op->stop;
- driver->start = op->start;
- driver->hangup = op->hangup;
- driver->break_ctl = op->break_ctl;
- driver->flush_buffer = op->flush_buffer;
- driver->set_ldisc = op->set_ldisc;
- driver->wait_until_sent = op->wait_until_sent;
- driver->send_xchar = op->send_xchar;
- driver->read_proc = op->read_proc;
- driver->write_proc = op->write_proc;
- driver->tiocmget = op->tiocmget;
- driver->tiocmset = op->tiocmset;
-#ifdef CONFIG_CONSOLE_POLL
- driver->poll_init = op->poll_init;
- driver->poll_get_char = op->poll_get_char;
- driver->poll_put_char = op->poll_put_char;
-#endif
-}
-
+ driver->ops = op;
+};
EXPORT_SYMBOL(alloc_tty_driver);
EXPORT_SYMBOL(put_tty_driver);
@@ -3961,9 +4004,6 @@ int tty_register_driver(struct tty_driver *driver)
return error;
}
- if (!driver->put_char)
- driver->put_char = tty_default_put_char;
-
mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
mutex_unlock(&tty_mutex);
@@ -4039,14 +4079,19 @@ void proc_clear_tty(struct task_struct *p)
}
EXPORT_SYMBOL(proc_clear_tty);
+/* Called under the sighand lock */
+
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
if (tty) {
- /* We should not have a session or pgrp to here but.... */
+ unsigned long flags;
+ /* We should not have a session or pgrp to put here but.... */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
- tty->session = get_pid(task_session(tsk));
tty->pgrp = get_pid(task_pgrp(tsk));
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ tty->session = get_pid(task_session(tsk));
}
put_pid(tsk->signal->tty_old_pgrp);
tsk->signal->tty = tty;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index f95a80b2265f..b1a757a5ee27 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -39,6 +40,50 @@
#define TERMIOS_OLD 8
+int tty_chars_in_buffer(struct tty_struct *tty)
+{
+ if (tty->ops->chars_in_buffer)
+ return tty->ops->chars_in_buffer(tty);
+ else
+ return 0;
+}
+
+EXPORT_SYMBOL(tty_chars_in_buffer);
+
+int tty_write_room(struct tty_struct *tty)
+{
+ if (tty->ops->write_room)
+ return tty->ops->write_room(tty);
+ return 2048;
+}
+
+EXPORT_SYMBOL(tty_write_room);
+
+void tty_driver_flush_buffer(struct tty_struct *tty)
+{
+ if (tty->ops->flush_buffer)
+ tty->ops->flush_buffer(tty);
+}
+
+EXPORT_SYMBOL(tty_driver_flush_buffer);
+
+void tty_throttle(struct tty_struct *tty)
+{
+ /* check TTY_THROTTLED first so it indicates our state */
+ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->ops->throttle)
+ tty->ops->throttle(tty);
+}
+EXPORT_SYMBOL(tty_throttle);
+
+void tty_unthrottle(struct tty_struct *tty)
+{
+ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->ops->unthrottle)
+ tty->ops->unthrottle(tty);
+}
+EXPORT_SYMBOL(tty_unthrottle);
+
/**
* tty_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for
@@ -57,15 +102,13 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
#endif
- if (!tty->driver->chars_in_buffer)
- return;
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
if (wait_event_interruptible_timeout(tty->write_wait,
- !tty->driver->chars_in_buffer(tty), timeout) < 0)
- return;
- if (tty->driver->wait_until_sent)
- tty->driver->wait_until_sent(tty, timeout);
+ !tty_chars_in_buffer(tty), timeout) >= 0) {
+ if (tty->ops->wait_until_sent)
+ tty->ops->wait_until_sent(tty, timeout);
+ }
}
EXPORT_SYMBOL(tty_wait_until_sent);
@@ -393,8 +436,9 @@ EXPORT_SYMBOL(tty_termios_hw_change);
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
int canon_change;
- struct ktermios old_termios = *tty->termios;
+ struct ktermios old_termios;
struct tty_ldisc *ld;
+ unsigned long flags;
/*
* Perform the actual termios internal changes under lock.
@@ -404,7 +448,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
mutex_lock(&tty->termios_mutex);
-
+ old_termios = *tty->termios;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@ -429,17 +473,19 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if (old_flow != new_flow) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
wake_up_interruptible(&tty->link->read_wait);
}
}
- if (tty->driver->set_termios)
- (*tty->driver->set_termios)(tty, &old_termios);
+ if (tty->ops->set_termios)
+ (*tty->ops->set_termios)(tty, &old_termios);
else
tty_termios_copy_hw(tty->termios, &old_termios);
@@ -474,7 +520,9 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
if (retval)
return retval;
+ mutex_lock(&tty->termios_mutex);
memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+ mutex_unlock(&tty->termios_mutex);
if (opt & TERMIOS_TERMIO) {
if (user_termio_to_kernel_termios(&tmp_termios,
@@ -660,12 +708,14 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
{
struct tchars tmp;
+ mutex_lock(&tty->termios_mutex);
tmp.t_intrc = tty->termios->c_cc[VINTR];
tmp.t_quitc = tty->termios->c_cc[VQUIT];
tmp.t_startc = tty->termios->c_cc[VSTART];
tmp.t_stopc = tty->termios->c_cc[VSTOP];
tmp.t_eofc = tty->termios->c_cc[VEOF];
tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -675,12 +725,14 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cc[VINTR] = tmp.t_intrc;
tty->termios->c_cc[VQUIT] = tmp.t_quitc;
tty->termios->c_cc[VSTART] = tmp.t_startc;
tty->termios->c_cc[VSTOP] = tmp.t_stopc;
tty->termios->c_cc[VEOF] = tmp.t_eofc;
tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
#endif
@@ -690,6 +742,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
{
struct ltchars tmp;
+ mutex_lock(&tty->termios_mutex);
tmp.t_suspc = tty->termios->c_cc[VSUSP];
/* what is dsuspc anyway? */
tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
@@ -698,6 +751,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
tmp.t_flushc = tty->termios->c_cc[VEOL2];
tmp.t_werasc = tty->termios->c_cc[VWERASE];
tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -708,6 +762,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cc[VSUSP] = tmp.t_suspc;
/* what is dsuspc anyway? */
tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
@@ -716,6 +771,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
tty->termios->c_cc[VEOL2] = tmp.t_flushc;
tty->termios->c_cc[VWERASE] = tmp.t_werasc;
tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
#endif
@@ -732,8 +788,8 @@ static int send_prio_char(struct tty_struct *tty, char ch)
{
int was_stopped = tty->stopped;
- if (tty->driver->send_xchar) {
- tty->driver->send_xchar(tty, ch);
+ if (tty->ops->send_xchar) {
+ tty->ops->send_xchar(tty, ch);
return 0;
}
@@ -742,7 +798,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
if (was_stopped)
start_tty(tty);
- tty->driver->write(tty, &ch, 1);
+ tty->ops->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
tty_write_unlock(tty);
@@ -750,6 +806,33 @@ static int send_prio_char(struct tty_struct *tty, char ch)
}
/**
+ * tty_change_softcar - carrier change ioctl helper
+ * @tty: tty to update
+ * @arg: enable/disable CLOCAL
+ *
+ * Perform a change to the CLOCAL state and call into the driver
+ * layer to make it visible. All done with the termios mutex
+ */
+
+static int tty_change_softcar(struct tty_struct *tty, int arg)
+{
+ int ret = 0;
+ int bit = arg ? CLOCAL : 0;
+ struct ktermios old;
+
+ mutex_lock(&tty->termios_mutex);
+ old = *tty->termios;
+ tty->termios->c_cflag &= ~CLOCAL;
+ tty->termios->c_cflag |= bit;
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old);
+ if ((tty->termios->c_cflag & CLOCAL) != bit)
+ ret = -EINVAL;
+ mutex_unlock(&tty->termios_mutex);
+ return ret;
+}
+
+/**
* tty_mode_ioctl - mode related ioctls
* @tty: tty for the ioctl
* @file: file pointer for the tty
@@ -859,12 +942,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
- mutex_lock(&tty->termios_mutex);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- mutex_unlock(&tty->termios_mutex);
- return 0;
+ return tty_change_softcar(tty, arg);
default:
return -ENOIOCTLCMD;
}
@@ -889,8 +967,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
ld->flush_buffer(tty);
/* fall through */
case TCOFLUSH:
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
break;
default:
tty_ldisc_deref(ld);
@@ -905,6 +982,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct tty_struct *real_tty;
+ unsigned long flags;
int retval;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -946,9 +1024,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
case TCFLSH:
return tty_perform_flush(tty, arg);
case TIOCOUTQ:
- return put_user(tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0,
- (int __user *) arg);
+ return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
retval = tty->read_cnt;
if (L_ICANON(tty))
@@ -963,6 +1039,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return -ENOTTY;
if (get_user(pktmode, (int __user *) arg))
return -EFAULT;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (pktmode) {
if (!tty->packet) {
tty->packet = 1;
@@ -970,6 +1047,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
}
} else
tty->packet = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return 0;
}
default:
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 8de6b95aeb84..3d3e1c2b310f 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -628,13 +628,13 @@ static int viotty_write(struct tty_struct *tty, const unsigned char *buf,
/*
* TTY put_char method
*/
-static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
+static int viotty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct port_info *pi;
pi = get_port_data(tty);
if (pi == NULL)
- return;
+ return 0;
/* This will append '\r' as well if the char is '\n' */
if (viochar_is_console(pi))
@@ -642,6 +642,7 @@ static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
if (viopath_isactive(pi->lp))
internal_write(pi, &ch, 1);
+ return 1;
}
/*
@@ -704,8 +705,11 @@ static int viotty_ioctl(struct tty_struct *tty, struct file *file,
case KDSKBLED:
return 0;
}
-
- return n_tty_ioctl(tty, file, cmd, arg);
+ /* FIXME: WTF is this being called for ??? */
+ lock_kernel();
+ ret = n_tty_ioctl(tty, file, cmd, arg);
+ unlock_kernel();
+ return ret;
}
/*
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index db7a731e2362..58aad63831f4 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -249,6 +249,7 @@ static int proc_viotape_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_viotape_operations = {
+ .owner = THIS_MODULE,
.open = proc_viotape_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -915,7 +916,6 @@ static struct vio_driver viotape_driver = {
int __init viotap_init(void)
{
int ret;
- struct proc_dir_entry *e;
if (!firmware_has_feature(FW_FEATURE_ISERIES))
return -ENODEV;
@@ -968,11 +968,8 @@ int __init viotap_init(void)
if (ret)
goto unreg_class;
- e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL);
- if (e) {
- e->owner = THIS_MODULE;
- e->proc_fops = &proc_viotape_operations;
- }
+ proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL,
+ &proc_viotape_operations);
return 0;
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index e122a0e87bb0..f17ac043b551 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -89,9 +89,7 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state);
static struct tty_driver *scc_driver;
-struct scc_port scc_ports[2];
-
-int scc_initialized = 0;
+static struct scc_port scc_ports[2];
/*---------------------------------------------------------------------------
* Interface from generic_serial.c back here
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index df4c3ead9e2b..fa1ffbf2c621 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+ scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char,
vc->vc_size_row * nr);
}
@@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr;
scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
+ scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step);
}
static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -400,7 +400,7 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
* Bit 7 : blink
*/
{
- u8 a = vc->vc_color;
+ u8 a = _color;
if (!vc->vc_can_do_color)
return _intensity |
(_italic ? 2 : 0) |
@@ -434,6 +434,7 @@ static void update_attr(struct vc_data *vc)
vc->vc_blink, vc->vc_underline,
vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
+ vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, false, false) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
@@ -908,15 +909,21 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
if (vc->vc_tty) {
struct winsize ws, *cws = &vc->vc_tty->winsize;
+ unsigned long flags;
memset(&ws, 0, sizeof(ws));
ws.ws_row = vc->vc_rows;
ws.ws_col = vc->vc_cols;
ws.ws_ypixel = vc->vc_scan_lines;
+
+ mutex_lock(&vc->vc_tty->termios_mutex);
+ spin_lock_irqsave(&vc->vc_tty->ctrl_lock, flags);
if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
vc->vc_tty->pgrp)
kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
+ spin_unlock_irqrestore(&vc->vc_tty->ctrl_lock, flags);
*cws = ws;
+ mutex_unlock(&vc->vc_tty->termios_mutex);
}
if (CON_IS_VISIBLE(vc))
@@ -2540,6 +2547,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
if (get_user(type, p))
return -EFAULT;
ret = 0;
+
+ lock_kernel();
+
switch (type)
{
case TIOCL_SETSEL:
@@ -2559,7 +2569,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
ret = sel_loadlut(p);
break;
case TIOCL_GETSHIFTSTATE:
-
+
/*
* Make it possible to react to Shift+Mousebutton.
* Note that 'shift_state' is an undocumented
@@ -2614,6 +2624,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
ret = -EINVAL;
break;
}
+ unlock_kernel();
return ret;
}
@@ -2631,11 +2642,11 @@ static int con_write(struct tty_struct *tty, const unsigned char *buf, int count
return retval;
}
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
+static int con_put_char(struct tty_struct *tty, unsigned char ch)
{
if (in_interrupt())
- return; /* n_r3964 calls put_char() from interrupt context */
- do_con_write(tty, &ch, 1);
+ return 0; /* n_r3964 calls put_char() from interrupt context */
+ return do_con_write(tty, &ch, 1);
}
static int con_write_room(struct tty_struct *tty)
@@ -2731,6 +2742,10 @@ static int con_open(struct tty_struct *tty, struct file *filp)
tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
+ if (vc->vc_utf)
+ tty->termios->c_iflag |= IUTF8;
+ else
+ tty->termios->c_iflag &= ~IUTF8;
release_console_sem();
vcs_make_sysfs(tty);
return ret;
@@ -2907,6 +2922,8 @@ int __init vty_init(void)
console_driver->minor_start = 1;
console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
console_driver->init_termios = tty_std_termios;
+ if (default_utf8)
+ console_driver->init_termios.c_iflag |= IUTF8;
console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(console_driver, &con_ops);
if (tty_register_driver(console_driver))
@@ -3828,7 +3845,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
goto out;
c = (font.width+7)/8 * 32 * font.charcount;
-
+
if (op->data && font.charcount > op->charcount)
rc = -ENOSPC;
if (!(op->flags & KD_FONT_FLAG_OLD)) {
@@ -3993,6 +4010,7 @@ u16 screen_glyph(struct vc_data *vc, int offset)
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);
/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index e6f89e8b9258..3211afd9d57e 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -373,11 +373,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned char ucval;
void __user *up = (void __user *)arg;
int i, perm;
-
+ int ret = 0;
+
console = vc->vc_num;
- if (!vc_cons_allocated(console)) /* impossible? */
- return -ENOIOCTLCMD;
+ lock_kernel();
+
+ if (!vc_cons_allocated(console)) { /* impossible? */
+ ret = -ENOIOCTLCMD;
+ goto out;
+ }
+
/*
* To have permissions to do most of the vt ioctls, we either have
@@ -391,15 +397,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd) {
case KIOCSOUND:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg)
arg = CLOCK_TICK_RATE / arg;
kd_mksound(arg, 0);
- return 0;
+ break;
case KDMKTONE:
if (!perm)
- return -EPERM;
+ goto eperm;
{
unsigned int ticks, count;
@@ -412,7 +418,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (count)
count = CLOCK_TICK_RATE / count;
kd_mksound(count, ticks);
- return 0;
+ break;
}
case KDGKBTYPE:
@@ -435,14 +441,18 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* KDADDIO and KDDELIO may be able to add ports beyond what
* we reject here, but to be safe...
*/
- if (arg < GPFIRST || arg > GPLAST)
- return -EINVAL;
- return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+ if (arg < GPFIRST || arg > GPLAST) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+ break;
case KDENABIO:
case KDDISABIO:
- return sys_ioperm(GPFIRST, GPNUM,
+ ret = sys_ioperm(GPFIRST, GPNUM,
(cmd == KDENABIO)) ? -ENXIO : 0;
+ break;
#endif
/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
@@ -450,19 +460,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDKBDREP:
{
struct kbd_repeat kbrep;
- int err;
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
- if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat)))
- return -EFAULT;
- err = kbd_rate(&kbrep);
- if (err)
- return err;
+ if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = kbd_rate(&kbrep);
+ if (ret)
+ break;
if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
case KDSETMODE:
@@ -475,7 +486,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* need to restore their engine state. --BenH
*/
if (!perm)
- return -EPERM;
+ goto eperm;
switch (arg) {
case KD_GRAPHICS:
break;
@@ -485,13 +496,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KD_TEXT:
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (vc->vc_mode == (unsigned char) arg)
- return 0;
+ break;
vc->vc_mode = (unsigned char) arg;
if (console != fg_console)
- return 0;
+ break;
/*
* explicitly blank/unblank the screen if switching modes
*/
@@ -501,7 +513,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
else
do_blank_screen(1);
release_console_sem();
- return 0;
+ break;
case KDGETMODE:
ucval = vc->vc_mode;
@@ -513,11 +525,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* these work like a combination of mmap and KDENABIO.
* this could be easily finished.
*/
- return -EINVAL;
+ ret = -EINVAL;
+ break;
case KDSKBMODE:
if (!perm)
- return -EPERM;
+ goto eperm;
switch(arg) {
case K_RAW:
kbd->kbdmode = VC_RAW;
@@ -534,10 +547,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
compute_shiftstate();
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
tty_ldisc_flush(tty);
- return 0;
+ break;
case KDGKBMODE:
ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
@@ -557,28 +571,32 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
set_vc_kbd_mode(kbd, VC_META);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ break;
case KDGKBMETA:
ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
setint:
- return put_user(ucval, (int __user *)arg);
+ ret = put_user(ucval, (int __user *)arg);
+ break;
case KDGETKEYCODE:
case KDSETKEYCODE:
if(!capable(CAP_SYS_TTY_CONFIG))
- perm=0;
- return do_kbkeycode_ioctl(cmd, up, perm);
+ perm = 0;
+ ret = do_kbkeycode_ioctl(cmd, up, perm);
+ break;
case KDGKBENT:
case KDSKBENT:
- return do_kdsk_ioctl(cmd, up, perm, kbd);
+ ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+ break;
case KDGKBSENT:
case KDSKBSENT:
- return do_kdgkb_ioctl(cmd, up, perm);
+ ret = do_kdgkb_ioctl(cmd, up, perm);
+ break;
case KDGKBDIACR:
{
@@ -586,26 +604,31 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct kbdiacr diacr;
int i;
- if (put_user(accent_table_size, &a->kb_cnt))
- return -EFAULT;
+ if (put_user(accent_table_size, &a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
for (i = 0; i < accent_table_size; i++) {
diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
diacr.base = conv_uni_to_8bit(accent_table[i].base);
diacr.result = conv_uni_to_8bit(accent_table[i].result);
- if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
- return -EFAULT;
+ if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
+ ret = -EFAULT;
+ break;
+ }
}
- return 0;
+ break;
}
case KDGKBDIACRUC:
{
struct kbdiacrsuc __user *a = up;
if (put_user(accent_table_size, &a->kb_cnt))
- return -EFAULT;
- if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ else if (copy_to_user(a->kbdiacruc, accent_table,
+ accent_table_size*sizeof(struct kbdiacruc)))
+ ret = -EFAULT;
+ break;
}
case KDSKBDIACR:
@@ -616,20 +639,26 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
int i;
if (!perm)
- return -EPERM;
- if (get_user(ct,&a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ goto eperm;
+ if (get_user(ct,&a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (ct >= MAX_DIACR) {
+ ret = -EINVAL;
+ break;
+ }
accent_table_size = ct;
for (i = 0; i < ct; i++) {
- if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
- return -EFAULT;
+ if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
+ ret = -EFAULT;
+ break;
+ }
accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
accent_table[i].base = conv_8bit_to_uni(diacr.base);
accent_table[i].result = conv_8bit_to_uni(diacr.result);
}
- return 0;
+ break;
}
case KDSKBDIACRUC:
@@ -638,15 +667,19 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int ct;
if (!perm)
- return -EPERM;
- if (get_user(ct,&a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ goto eperm;
+ if (get_user(ct,&a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (ct >= MAX_DIACR) {
+ ret = -EINVAL;
+ break;
+ }
accent_table_size = ct;
if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
/* the ioctls below read/set the flags usually shown in the leds */
@@ -657,26 +690,29 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSKBLED:
if (!perm)
- return -EPERM;
- if (arg & ~0x77)
- return -EINVAL;
+ goto eperm;
+ if (arg & ~0x77) {
+ ret = -EINVAL;
+ break;
+ }
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
- return 0;
+ break;
/* the ioctls below only set the lights, not the functions */
/* for those, see KDGKBLED and KDSKBLED above */
case KDGETLED:
ucval = getledstate();
setchar:
- return put_user(ucval, (char __user *)arg);
+ ret = put_user(ucval, (char __user *)arg);
+ break;
case KDSETLED:
if (!perm)
- return -EPERM;
+ goto eperm;
setledstate(kbd, arg);
- return 0;
+ break;
/*
* A process can indicate its willingness to accept signals
@@ -688,16 +724,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSIGACCEPT:
{
if (!perm || !capable(CAP_KILL))
- return -EPERM;
+ goto eperm;
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
- return -EINVAL;
-
- spin_lock_irq(&vt_spawn_con.lock);
- put_pid(vt_spawn_con.pid);
- vt_spawn_con.pid = get_pid(task_pid(current));
- vt_spawn_con.sig = arg;
- spin_unlock_irq(&vt_spawn_con.lock);
- return 0;
+ ret = -EINVAL;
+ else {
+ spin_lock_irq(&vt_spawn_con.lock);
+ put_pid(vt_spawn_con.pid);
+ vt_spawn_con.pid = get_pid(task_pid(current));
+ vt_spawn_con.sig = arg;
+ spin_unlock_irq(&vt_spawn_con.lock);
+ }
+ break;
}
case VT_SETMODE:
@@ -705,11 +742,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct vt_mode tmp;
if (!perm)
- return -EPERM;
- if (copy_from_user(&tmp, up, sizeof(struct vt_mode)))
- return -EFAULT;
- if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
- return -EINVAL;
+ goto eperm;
+ if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+ ret = -EINVAL;
+ goto out;
+ }
acquire_console_sem();
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
@@ -719,7 +760,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
release_console_sem();
- return 0;
+ break;
}
case VT_GETMODE:
@@ -732,7 +773,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
release_console_sem();
rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
- return rc ? -EFAULT : 0;
+ if (rc)
+ ret = -EFAULT;
+ break;
}
/*
@@ -746,12 +789,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned short state, mask;
if (put_user(fg_console + 1, &vtstat->v_active))
- return -EFAULT;
- state = 1; /* /dev/tty0 is always open */
- for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
- if (VT_IS_IN_USE(i))
- state |= mask;
- return put_user(state, &vtstat->v_state);
+ ret = -EFAULT;
+ else {
+ state = 1; /* /dev/tty0 is always open */
+ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+ ++i, mask <<= 1)
+ if (VT_IS_IN_USE(i))
+ state |= mask;
+ ret = put_user(state, &vtstat->v_state);
+ }
+ break;
}
/*
@@ -771,27 +818,31 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
case VT_ACTIVATE:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- return -ENXIO;
- arg--;
- acquire_console_sem();
- i = vc_allocate(arg);
- release_console_sem();
- if (i)
- return i;
- set_console(arg);
- return 0;
+ ret = -ENXIO;
+ else {
+ arg--;
+ acquire_console_sem();
+ ret = vc_allocate(arg);
+ release_console_sem();
+ if (ret)
+ break;
+ set_console(arg);
+ }
+ break;
/*
* wait until the specified VT has been activated
*/
case VT_WAITACTIVE:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- return -ENXIO;
- return vt_waitactive(arg-1);
+ ret = -ENXIO;
+ else
+ ret = vt_waitactive(arg - 1);
+ break;
/*
* If a vt is under process control, the kernel will not switch to it
@@ -805,10 +856,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
case VT_RELDISP:
if (!perm)
- return -EPERM;
- if (vc->vt_mode.mode != VT_PROCESS)
- return -EINVAL;
+ goto eperm;
+ if (vc->vt_mode.mode != VT_PROCESS) {
+ ret = -EINVAL;
+ break;
+ }
/*
* Switching-from response
*/
@@ -829,10 +882,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
int newvt;
newvt = vc->vt_newvt;
vc->vt_newvt = -1;
- i = vc_allocate(newvt);
- if (i) {
+ ret = vc_allocate(newvt);
+ if (ret) {
release_console_sem();
- return i;
+ break;
}
/*
* When we actually do the console switch,
@@ -841,31 +894,27 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
complete_change_console(vc_cons[newvt].d);
}
- }
-
- /*
- * Switched-to response
- */
- else
- {
+ } else {
+ /*
+ * Switched-to response
+ */
/*
* If it's just an ACK, ignore it
*/
- if (arg != VT_ACKACQ) {
- release_console_sem();
- return -EINVAL;
- }
+ if (arg != VT_ACKACQ)
+ ret = -EINVAL;
}
release_console_sem();
-
- return 0;
+ break;
/*
* Disallocate memory associated to VT (but leave VT1)
*/
case VT_DISALLOCATE:
- if (arg > MAX_NR_CONSOLES)
- return -ENXIO;
+ if (arg > MAX_NR_CONSOLES) {
+ ret = -ENXIO;
+ break;
+ }
if (arg == 0) {
/* deallocate all unused consoles, but leave 0 */
acquire_console_sem();
@@ -877,14 +926,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
/* deallocate a single console, if possible */
arg--;
if (VT_BUSY(arg))
- return -EBUSY;
- if (arg) { /* leave 0 */
+ ret = -EBUSY;
+ else if (arg) { /* leave 0 */
acquire_console_sem();
vc_deallocate(arg);
release_console_sem();
}
}
- return 0;
+ break;
case VT_RESIZE:
{
@@ -893,21 +942,21 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ushort ll,cc;
if (!perm)
- return -EPERM;
+ goto eperm;
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
- return -EFAULT;
-
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- vc = vc_cons[i].d;
+ ret = -EFAULT;
+ else {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ vc = vc_cons[i].d;
- if (vc) {
- vc->vc_resize_user = 1;
- vc_lock_resize(vc_cons[i].d, cc, ll);
+ if (vc) {
+ vc->vc_resize_user = 1;
+ vc_lock_resize(vc_cons[i].d, cc, ll);
+ }
}
}
-
- return 0;
+ break;
}
case VT_RESIZEX:
@@ -915,10 +964,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct vt_consize __user *vtconsize = up;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
- return -EPERM;
+ goto eperm;
if (!access_ok(VERIFY_READ, vtconsize,
- sizeof(struct vt_consize)))
- return -EFAULT;
+ sizeof(struct vt_consize))) {
+ ret = -EFAULT;
+ break;
+ }
+ /* FIXME: Should check the copies properly */
__get_user(ll, &vtconsize->v_rows);
__get_user(cc, &vtconsize->v_cols);
__get_user(vlin, &vtconsize->v_vlin);
@@ -928,21 +980,28 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vlin = vlin ? vlin : vc->vc_scan_lines;
if (clin) {
if (ll) {
- if (ll != vlin/clin)
- return -EINVAL; /* Parameters don't add up */
+ if (ll != vlin/clin) {
+ /* Parameters don't add up */
+ ret = -EINVAL;
+ break;
+ }
} else
ll = vlin/clin;
}
if (vcol && ccol) {
if (cc) {
- if (cc != vcol/ccol)
- return -EINVAL;
+ if (cc != vcol/ccol) {
+ ret = -EINVAL;
+ break;
+ }
} else
cc = vcol/ccol;
}
- if (clin > 32)
- return -EINVAL;
+ if (clin > 32) {
+ ret = -EINVAL;
+ break;
+ }
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons[i].d)
@@ -956,19 +1015,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vc_resize(vc_cons[i].d, cc, ll);
release_console_sem();
}
- return 0;
+ break;
}
case PIO_FONT: {
if (!perm)
- return -EPERM;
+ goto eperm;
op.op = KD_FONT_OP_SET;
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
op.width = 8;
op.height = 0;
op.charcount = 256;
op.data = up;
- return con_font_op(vc_cons[fg_console].d, &op);
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ break;
}
case GIO_FONT: {
@@ -978,100 +1038,124 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
op.height = 32;
op.charcount = 256;
op.data = up;
- return con_font_op(vc_cons[fg_console].d, &op);
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ break;
}
case PIO_CMAP:
if (!perm)
- return -EPERM;
- return con_set_cmap(up);
+ ret = -EPERM;
+ else
+ ret = con_set_cmap(up);
+ break;
case GIO_CMAP:
- return con_get_cmap(up);
+ ret = con_get_cmap(up);
+ break;
case PIO_FONTX:
case GIO_FONTX:
- return do_fontx_ioctl(cmd, up, perm, &op);
+ ret = do_fontx_ioctl(cmd, up, perm, &op);
+ break;
case PIO_FONTRESET:
{
if (!perm)
- return -EPERM;
+ goto eperm;
#ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
font is not saved. */
- return -ENOSYS;
+ ret = -ENOSYS;
+ break;
#else
{
op.op = KD_FONT_OP_SET_DEFAULT;
op.data = NULL;
- i = con_font_op(vc_cons[fg_console].d, &op);
- if (i)
- return i;
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ if (ret)
+ break;
con_set_default_unimap(vc_cons[fg_console].d);
- return 0;
+ break;
}
#endif
}
case KDFONTOP: {
- if (copy_from_user(&op, up, sizeof(op)))
- return -EFAULT;
+ if (copy_from_user(&op, up, sizeof(op))) {
+ ret = -EFAULT;
+ break;
+ }
if (!perm && op.op != KD_FONT_OP_GET)
- return -EPERM;
- i = con_font_op(vc, &op);
- if (i) return i;
+ goto eperm;
+ ret = con_font_op(vc, &op);
+ if (ret)
+ break;
if (copy_to_user(up, &op, sizeof(op)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
case PIO_SCRNMAP:
if (!perm)
- return -EPERM;
- return con_set_trans_old(up);
+ ret = -EPERM;
+ else
+ ret = con_set_trans_old(up);
+ break;
case GIO_SCRNMAP:
- return con_get_trans_old(up);
+ ret = con_get_trans_old(up);
+ break;
case PIO_UNISCRNMAP:
if (!perm)
- return -EPERM;
- return con_set_trans_new(up);
+ ret = -EPERM;
+ else
+ ret = con_set_trans_new(up);
+ break;
case GIO_UNISCRNMAP:
- return con_get_trans_new(up);
+ ret = con_get_trans_new(up);
+ break;
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
- return -EPERM;
- i = copy_from_user(&ui, up, sizeof(struct unimapinit));
- if (i) return -EFAULT;
- con_clear_unimap(vc, &ui);
- return 0;
+ goto eperm;
+ ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
+ if (!ret)
+ con_clear_unimap(vc, &ui);
+ break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
- return do_unimap_ioctl(cmd, up, perm, vc);
+ ret = do_unimap_ioctl(cmd, up, perm, vc);
+ break;
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
vt_dont_switch = 1;
- return 0;
+ break;
case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
vt_dont_switch = 0;
- return 0;
+ break;
case VT_GETHIFONTMASK:
- return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg);
+ ret = put_user(vc->vc_hi_font_mask,
+ (unsigned short __user *)arg);
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
+out:
+ unlock_kernel();
+ return ret;
+eperm:
+ ret = -EPERM;
+ goto out;
}
/*
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index dfe6907ae15b..3edf1fc12963 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -623,8 +623,8 @@ static int __devinit hwicap_setup(struct device *dev, int id,
if (!request_mem_region(drvdata->mem_start,
drvdata->mem_size, DRIVER_NAME)) {
- dev_err(dev, "Couldn't lock memory region at %p\n",
- (void *)regs_res->start);
+ dev_err(dev, "Couldn't lock memory region at %Lx\n",
+ regs_res->start);
retval = -EBUSY;
goto failed1;
}
@@ -643,7 +643,7 @@ static int __devinit hwicap_setup(struct device *dev, int id,
mutex_init(&drvdata->sem);
drvdata->is_open = 0;
- dev_info(dev, "ioremap %lx to %p with size %x\n",
+ dev_info(dev, "ioremap %lx to %p with size %Lx\n",
(unsigned long int)drvdata->mem_start,
drvdata->base_address, drvdata->mem_size);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index c159ae64eeb2..5f076aef74fa 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -69,6 +69,15 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE
the frequency statically to the highest frequency supported by
the CPU.
+config CPU_FREQ_DEFAULT_GOV_POWERSAVE
+ bool "powersave"
+ depends on EMBEDDED
+ select CPU_FREQ_GOV_POWERSAVE
+ help
+ Use the CPUFreq governor 'powersave' as default. This sets
+ the frequency statically to the lowest frequency supported by
+ the CPU.
+
config CPU_FREQ_DEFAULT_GOV_USERSPACE
bool "userspace"
select CPU_FREQ_GOV_USERSPACE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index d3575f5ec6d2..7fce038fa57e 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -583,15 +583,13 @@ out:
i += sprintf(&buf[i], "\n");
return i;
}
-/**
- * show_affected_cpus - show the CPUs affected by each transition
- */
-static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
+
+static ssize_t show_cpus(cpumask_t mask, char *buf)
{
ssize_t i = 0;
unsigned int cpu;
- for_each_cpu_mask(cpu, policy->cpus) {
+ for_each_cpu_mask(cpu, mask) {
if (i)
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
@@ -602,6 +600,25 @@ static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
return i;
}
+/**
+ * show_related_cpus - show the CPUs affected by each transition even if
+ * hw coordination is in use
+ */
+static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
+{
+ if (cpus_empty(policy->related_cpus))
+ return show_cpus(policy->cpus, buf);
+ return show_cpus(policy->related_cpus, buf);
+}
+
+/**
+ * show_affected_cpus - show the CPUs affected by each transition
+ */
+static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
+{
+ return show_cpus(policy->cpus, buf);
+}
+
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
@@ -646,6 +663,7 @@ define_one_ro(cpuinfo_max_freq);
define_one_ro(scaling_available_governors);
define_one_ro(scaling_driver);
define_one_ro(scaling_cur_freq);
+define_one_ro(related_cpus);
define_one_ro(affected_cpus);
define_one_rw(scaling_min_freq);
define_one_rw(scaling_max_freq);
@@ -658,6 +676,7 @@ static struct attribute *default_attrs[] = {
&scaling_min_freq.attr,
&scaling_max_freq.attr,
&affected_cpus.attr,
+ &related_cpus.attr,
&scaling_governor.attr,
&scaling_driver.attr,
&scaling_available_governors.attr,
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 13fe06b94b0a..88d2f44fba48 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -35,12 +35,12 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
return 0;
}
-static struct cpufreq_governor cpufreq_gov_powersave = {
+struct cpufreq_governor cpufreq_gov_powersave = {
.name = "powersave",
.governor = cpufreq_governor_powersave,
.owner = THIS_MODULE,
};
-
+EXPORT_SYMBOL(cpufreq_gov_powersave);
static int __init cpufreq_gov_powersave_init(void)
{
@@ -58,5 +58,9 @@ MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'");
MODULE_LICENSE("GPL");
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE
+fs_initcall(cpufreq_gov_powersave_init);
+#else
module_init(cpufreq_gov_powersave_init);
+#endif
module_exit(cpufreq_gov_powersave_exit);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index ef09e069433b..ae70d63a8b26 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -288,7 +288,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
if (!stat)
return 0;
- old_index = freq_table_get_index(stat, freq->old);
+ old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
cpufreq_stats_update(freq->cpu);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 2b382990fe58..6e6c3c4aea6b 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -67,7 +67,7 @@ config EDAC_E7XXX
E7205, E7500, E7501 and E7505 server chipsets.
config EDAC_E752X
- tristate "Intel e752x (e7520, e7525, e7320)"
+ tristate "Intel e752x (e7520, e7525, e7320) and 3100"
depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG
help
Support for error detection and correction on the Intel
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index f22075410591..2b95f1a3edfc 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define AMD76X_REVISION " Ver: 2.0.2 " __DATE__
@@ -344,6 +345,9 @@ static struct pci_driver amd76x_driver = {
static int __init amd76x_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&amd76x_driver);
}
@@ -358,3 +362,6 @@ module_exit(amd76x_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
MODULE_DESCRIPTION("MC support for AMD 76x memory controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 6eb434749cd5..c94a0eb492cb 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -29,6 +29,7 @@
#define EDAC_MOD_STR "e752x_edac"
static int force_function_unhide;
+static int sysbus_parity = -1;
static struct edac_pci_ctl_info *e752x_pci;
@@ -62,6 +63,14 @@ static struct edac_pci_ctl_info *e752x_pci;
#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593
#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */
+#ifndef PCI_DEVICE_ID_INTEL_3100_0
+#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0
+#endif /* PCI_DEVICE_ID_INTEL_3100_0 */
+
+#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR
+#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1
+#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */
+
#define E752X_NR_CSROWS 8 /* number of csrows */
/* E752X register addresses - device 0 function 0 */
@@ -152,6 +161,12 @@ static struct edac_pci_ctl_info *e752x_pci;
/* error syndrome register (16b) */
#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */
+/* 3100 IMCH specific register addresses - device 0 function 1 */
+#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */
+#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */
+#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */
+#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */
+
/* ICH5R register addresses - device 30 function 0 */
#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */
#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */
@@ -160,7 +175,8 @@ static struct edac_pci_ctl_info *e752x_pci;
enum e752x_chips {
E7520 = 0,
E7525 = 1,
- E7320 = 2
+ E7320 = 2,
+ I3100 = 3
};
struct e752x_pvt {
@@ -185,8 +201,10 @@ struct e752x_dev_info {
struct e752x_error_info {
u32 ferr_global;
u32 nerr_global;
- u8 hi_ferr;
- u8 hi_nerr;
+ u32 nsi_ferr; /* 3100 only */
+ u32 nsi_nerr; /* 3100 only */
+ u8 hi_ferr; /* all but 3100 */
+ u8 hi_nerr; /* all but 3100 */
u16 sysbus_ferr;
u16 sysbus_nerr;
u8 buf_ferr;
@@ -215,6 +233,10 @@ static const struct e752x_dev_info e752x_devs[] = {
.err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
.ctl_name = "E7320"},
+ [I3100] = {
+ .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR,
+ .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0,
+ .ctl_name = "3100"},
};
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
@@ -402,7 +424,7 @@ static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
static char *global_message[11] = {
"PCI Express C1", "PCI Express C", "PCI Express B1",
"PCI Express B", "PCI Express A1", "PCI Express A",
- "DMA Controler", "HUB Interface", "System Bus",
+ "DMA Controler", "HUB or NS Interface", "System Bus",
"DRAM Controler", "Internal Buffer"
};
@@ -455,6 +477,63 @@ static inline void hub_error(int fatal, u8 errors, int *error_found,
do_hub_error(fatal, errors);
}
+#define NSI_FATAL_MASK 0x0c080081
+#define NSI_NON_FATAL_MASK 0x23a0ba64
+#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK)
+
+static char *nsi_message[30] = {
+ "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */
+ "", /* reserved */
+ "NSI Parity Error", /* bit 2, non-fatal */
+ "", /* reserved */
+ "", /* reserved */
+ "Correctable Error Message", /* bit 5, non-fatal */
+ "Non-Fatal Error Message", /* bit 6, non-fatal */
+ "Fatal Error Message", /* bit 7, fatal */
+ "", /* reserved */
+ "Receiver Error", /* bit 9, non-fatal */
+ "", /* reserved */
+ "Bad TLP", /* bit 11, non-fatal */
+ "Bad DLLP", /* bit 12, non-fatal */
+ "REPLAY_NUM Rollover", /* bit 13, non-fatal */
+ "", /* reserved */
+ "Replay Timer Timeout", /* bit 15, non-fatal */
+ "", /* reserved */
+ "", /* reserved */
+ "", /* reserved */
+ "Data Link Protocol Error", /* bit 19, fatal */
+ "", /* reserved */
+ "Poisoned TLP", /* bit 21, non-fatal */
+ "", /* reserved */
+ "Completion Timeout", /* bit 23, non-fatal */
+ "Completer Abort", /* bit 24, non-fatal */
+ "Unexpected Completion", /* bit 25, non-fatal */
+ "Receiver Overflow", /* bit 26, fatal */
+ "Malformed TLP", /* bit 27, fatal */
+ "", /* reserved */
+ "Unsupported Request" /* bit 29, non-fatal */
+};
+
+static void do_nsi_error(int fatal, u32 errors)
+{
+ int i;
+
+ for (i = 0; i < 30; i++) {
+ if (errors & (1 << i))
+ printk(KERN_WARNING "%sError %s\n",
+ fatal_message[fatal], nsi_message[i]);
+ }
+}
+
+static inline void nsi_error(int fatal, u32 errors, int *error_found,
+ int handle_error)
+{
+ *error_found = 1;
+
+ if (handle_error)
+ do_nsi_error(fatal, errors);
+}
+
static char *membuf_message[4] = {
"Internal PMWB to DRAM parity",
"Internal PMWB to System Bus Parity",
@@ -546,6 +625,31 @@ static void e752x_check_hub_interface(struct e752x_error_info *info,
}
}
+static void e752x_check_ns_interface(struct e752x_error_info *info,
+ int *error_found, int handle_error)
+{
+ u32 stat32;
+
+ stat32 = info->nsi_ferr;
+ if (stat32 & NSI_ERR_MASK) { /* Error, so process */
+ if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */
+ nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
+ handle_error);
+ if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */
+ nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
+ handle_error);
+ }
+ stat32 = info->nsi_nerr;
+ if (stat32 & NSI_ERR_MASK) {
+ if (stat32 & NSI_FATAL_MASK)
+ nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
+ handle_error);
+ if (stat32 & NSI_NON_FATAL_MASK)
+ nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
+ handle_error);
+ }
+}
+
static void e752x_check_sysbus(struct e752x_error_info *info,
int *error_found, int handle_error)
{
@@ -653,7 +757,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
if (info->ferr_global) {
- pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr);
+ if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
+ pci_read_config_dword(dev, I3100_NSI_FERR,
+ &info->nsi_ferr);
+ info->hi_ferr = 0;
+ } else {
+ pci_read_config_byte(dev, E752X_HI_FERR,
+ &info->hi_ferr);
+ info->nsi_ferr = 0;
+ }
pci_read_config_word(dev, E752X_SYSBUS_FERR,
&info->sysbus_ferr);
pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
@@ -669,10 +781,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
pci_read_config_dword(dev, E752X_DRAM_RETR_ADD,
&info->dram_retr_add);
+ /* ignore the reserved bits just in case */
if (info->hi_ferr & 0x7f)
pci_write_config_byte(dev, E752X_HI_FERR,
info->hi_ferr);
+ if (info->nsi_ferr & NSI_ERR_MASK)
+ pci_write_config_dword(dev, I3100_NSI_FERR,
+ info->nsi_ferr);
+
if (info->sysbus_ferr)
pci_write_config_word(dev, E752X_SYSBUS_FERR,
info->sysbus_ferr);
@@ -692,7 +809,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global);
if (info->nerr_global) {
- pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr);
+ if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
+ pci_read_config_dword(dev, I3100_NSI_NERR,
+ &info->nsi_nerr);
+ info->hi_nerr = 0;
+ } else {
+ pci_read_config_byte(dev, E752X_HI_NERR,
+ &info->hi_nerr);
+ info->nsi_nerr = 0;
+ }
pci_read_config_word(dev, E752X_SYSBUS_NERR,
&info->sysbus_nerr);
pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
@@ -706,6 +831,10 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
pci_write_config_byte(dev, E752X_HI_NERR,
info->hi_nerr);
+ if (info->nsi_nerr & NSI_ERR_MASK)
+ pci_write_config_dword(dev, I3100_NSI_NERR,
+ info->nsi_nerr);
+
if (info->sysbus_nerr)
pci_write_config_word(dev, E752X_SYSBUS_NERR,
info->sysbus_nerr);
@@ -750,6 +879,7 @@ static int e752x_process_error_info(struct mem_ctl_info *mci,
global_error(0, stat32, &error_found, handle_errors);
e752x_check_hub_interface(info, &error_found, handle_errors);
+ e752x_check_ns_interface(info, &error_found, handle_errors);
e752x_check_sysbus(info, &error_found, handle_errors);
e752x_check_membuf(info, &error_found, handle_errors);
e752x_check_dram(mci, info, &error_found, handle_errors);
@@ -920,15 +1050,53 @@ fail:
return 1;
}
+/* Setup system bus parity mask register.
+ * Sysbus parity supported on:
+ * e7320/e7520/e7525 + Xeon
+ * i3100 + Xeon/Celeron
+ * Sysbus parity not supported on:
+ * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo
+ */
+static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
+{
+ char *cpu_id = cpu_data(0).x86_model_id;
+ struct pci_dev *dev = pvt->dev_d0f1;
+ int enable = 1;
+
+ /* Allow module paramter override, else see if CPU supports parity */
+ if (sysbus_parity != -1) {
+ enable = sysbus_parity;
+ } else if (cpu_id[0] &&
+ ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) ||
+ (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) ||
+ (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) {
+ e752x_printk(KERN_INFO, "System Bus Parity not "
+ "supported by CPU, disabling\n");
+ enable = 0;
+ }
+
+ if (enable)
+ pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000);
+ else
+ pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309);
+}
+
static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
{
struct pci_dev *dev;
dev = pvt->dev_d0f1;
/* Turn off error disable & SMI in case the BIOS turned it on */
- pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
- pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
- pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00);
+ if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
+ pci_write_config_dword(dev, I3100_NSI_EMASK, 0);
+ pci_write_config_dword(dev, I3100_NSI_SMICMD, 0);
+ } else {
+ pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
+ pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
+ }
+
+ e752x_init_sysbus_parity_mask(pvt);
+
pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
@@ -949,16 +1117,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
debugf0("%s(): mci\n", __func__);
debugf0("Starting Probe1\n");
- /* make sure error reporting method is sane */
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
/* check to see if device 0 function 1 is enabled; if it isn't, we
* assume the BIOS has reserved it for a reason and is expecting
* exclusive access, we take care not to violate that assumption and
@@ -985,8 +1143,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): init mci\n", __func__);
mci->mtype_cap = MEM_FLAG_RDDR;
- mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
- EDAC_FLAG_S4ECD4ED;
+ /* 3100 IMCH supports SECDEC only */
+ mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
+ (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED);
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = E752X_REVISION;
@@ -1018,7 +1177,10 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
e752x_init_csrows(mci, pdev, ddrcsr);
e752x_init_mem_map_table(pdev, pvt);
- mci->edac_cap |= EDAC_FLAG_NONE;
+ if (dev_idx == I3100)
+ mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
+ else
+ mci->edac_cap |= EDAC_FLAG_NONE;
debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
/* load the top of low memory, remap base, and remap limit vars */
@@ -1110,6 +1272,9 @@ static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7320},
{
+ PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I3100},
+ {
0,
} /* 0 terminated list. */
};
@@ -1128,6 +1293,10 @@ static int __init e752x_init(void)
int pci_rc;
debugf3("%s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&e752x_driver);
return (pci_rc < 0) ? pci_rc : 0;
}
@@ -1143,10 +1312,15 @@ module_exit(e752x_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
-MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
+MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers");
module_param(force_function_unhide, int, 0444);
MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
+
module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+
+module_param(sysbus_parity, int, 0444);
+MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking,"
+ " 1=enable system bus parity checking, default=auto-detect");
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 96ecc4926641..c7d11cc4e21a 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -414,16 +414,6 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
debugf0("%s(): mci\n", __func__);
- /* make sure error reporting method is sane */
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
pci_read_config_dword(pdev, E7XXX_DRC, &drc);
drc_chan = dual_channel_active(drc, dev_idx);
@@ -565,6 +555,9 @@ static struct pci_driver e7xxx_driver = {
static int __init e7xxx_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&e7xxx_driver);
}
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index a9aa845dbe74..b27b13c5eb5a 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -97,7 +97,7 @@ extern int edac_debug_level;
#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
PCI_DEVICE_ID_ ## vend ## _ ## dev
-#define dev_name(dev) (dev)->dev_name
+#define edac_dev_name(dev) (dev)->dev_name
/* memory devices */
enum dev_type {
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index b9552bc03dea..5fcd3d89c75d 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -36,7 +36,7 @@
* is protected by the 'device_ctls_mutex' lock
*/
static DEFINE_MUTEX(device_ctls_mutex);
-static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list);
+static LIST_HEAD(edac_device_list);
#ifdef CONFIG_EDAC_DEBUG
static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
@@ -333,7 +333,7 @@ static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
fail0:
edac_printk(KERN_WARNING, EDAC_MC,
"%s (%s) %s %s already assigned %d\n",
- rover->dev->bus_id, dev_name(rover),
+ rover->dev->bus_id, edac_dev_name(rover),
rover->mod_name, rover->ctl_name, rover->dev_idx);
return 1;
@@ -375,37 +375,6 @@ static void del_edac_device_from_global_list(struct edac_device_ctl_info
wait_for_completion(&edac_device->removal_complete);
}
-/**
- * edac_device_find
- * Search for a edac_device_ctl_info structure whose index is 'idx'.
- *
- * If found, return a pointer to the structure.
- * Else return NULL.
- *
- * Caller must hold device_ctls_mutex.
- */
-struct edac_device_ctl_info *edac_device_find(int idx)
-{
- struct list_head *item;
- struct edac_device_ctl_info *edac_dev;
-
- /* Iterate over list, looking for exact match of ID */
- list_for_each(item, &edac_device_list) {
- edac_dev = list_entry(item, struct edac_device_ctl_info, link);
-
- if (edac_dev->dev_idx >= idx) {
- if (edac_dev->dev_idx == idx)
- return edac_dev;
-
- /* not on list, so terminate early */
- break;
- }
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(edac_device_find);
-
/*
* edac_device_workq_function
* performs the operation scheduled by a workq request
@@ -569,7 +538,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
"'%s': DEV '%s' (%s)\n",
edac_dev->mod_name,
edac_dev->ctl_name,
- dev_name(edac_dev),
+ edac_dev_name(edac_dev),
edac_op_state_to_string(edac_dev->op_state));
mutex_unlock(&device_ctls_mutex);
@@ -630,7 +599,7 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
edac_printk(KERN_INFO, EDAC_MC,
"Removed device %d for %s %s: DEV %s\n",
edac_dev->dev_idx,
- edac_dev->mod_name, edac_dev->ctl_name, dev_name(edac_dev));
+ edac_dev->mod_name, edac_dev->ctl_name, edac_dev_name(edac_dev));
return edac_dev;
}
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 063a1bffe38b..d110392d48f4 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -36,7 +36,7 @@
/* lock to memory controller's control array */
static DEFINE_MUTEX(mem_ctls_mutex);
-static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
+static LIST_HEAD(mc_devices);
#ifdef CONFIG_EDAC_DEBUG
@@ -402,7 +402,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
fail0:
edac_printk(KERN_WARNING, EDAC_MC,
"%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
- dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
+ edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
return 1;
fail1:
@@ -517,7 +517,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
/* Report action taken */
edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
- " DEV %s\n", mci->mod_name, mci->ctl_name, dev_name(mci));
+ " DEV %s\n", mci->mod_name, mci->ctl_name, edac_dev_name(mci));
mutex_unlock(&mem_ctls_mutex);
return 0;
@@ -565,7 +565,7 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
edac_printk(KERN_INFO, EDAC_MC,
"Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
- mci->mod_name, mci->ctl_name, dev_name(mci));
+ mci->mod_name, mci->ctl_name, edac_dev_name(mci));
return mci;
}
@@ -886,24 +886,3 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
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
- */
-void edac_check_mc_devices(void)
-{
- struct list_head *item;
- struct mem_ctl_info *mci;
-
- debugf3("%s()\n", __func__);
- mutex_lock(&mem_ctls_mutex);
-
- list_for_each(item, &mc_devices) {
- mci = list_entry(item, struct mem_ctl_info, link);
-
- if (mci->edac_check != NULL)
- mci->edac_check(mci);
- }
-
- mutex_unlock(&mem_ctls_mutex);
-}
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index cbc419c8ebc1..233d4798c3aa 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -27,7 +27,6 @@ extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
-extern void edac_check_mc_devices(void);
extern int edac_get_log_ue(void);
extern int edac_get_log_ce(void);
extern int edac_get_panic_on_ue(void);
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index 32be43576a8e..22ec9d5d4312 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -29,7 +29,7 @@
#include "edac_module.h"
static DEFINE_MUTEX(edac_pci_ctls_mutex);
-static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
+static LIST_HEAD(edac_pci_list);
/*
* edac_pci_alloc_ctl_info
@@ -150,7 +150,7 @@ static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
fail0:
edac_printk(KERN_WARNING, EDAC_PCI,
"%s (%s) %s %s already assigned %d\n",
- rover->dev->bus_id, dev_name(rover),
+ rover->dev->bus_id, edac_dev_name(rover),
rover->mod_name, rover->ctl_name, rover->pci_idx);
return 1;
@@ -189,6 +189,9 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
wait_for_completion(&pci->complete);
}
+#if 0
+/* Older code, but might use in the future */
+
/*
* edac_pci_find()
* Search for an edac_pci_ctl_info structure whose index is 'idx'
@@ -219,6 +222,7 @@ struct edac_pci_ctl_info *edac_pci_find(int idx)
return NULL;
}
EXPORT_SYMBOL_GPL(edac_pci_find);
+#endif
/*
* edac_pci_workq_function()
@@ -356,7 +360,7 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
" DEV '%s' (%s)\n",
pci->mod_name,
pci->ctl_name,
- dev_name(pci), edac_op_state_to_string(pci->op_state));
+ edac_dev_name(pci), edac_op_state_to_string(pci->op_state));
mutex_unlock(&edac_pci_ctls_mutex);
return 0;
@@ -411,7 +415,7 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
edac_printk(KERN_INFO, EDAC_PCI,
"Removed device %d for %s %s: DEV %s\n",
- pci->pci_idx, pci->mod_name, pci->ctl_name, dev_name(pci));
+ pci->pci_idx, pci->mod_name, pci->ctl_name, edac_dev_name(pci));
return pci;
}
@@ -422,7 +426,7 @@ EXPORT_SYMBOL_GPL(edac_pci_del_device);
*
* a Generic parity check API
*/
-void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
+static void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
{
debugf4("%s()\n", __func__);
edac_pci_do_parity_check();
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index 71c3195d3704..2c1fa1bb6df2 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -37,17 +37,17 @@ int edac_pci_get_check_errors(void)
return check_pci_errors;
}
-int edac_pci_get_log_pe(void)
+static int edac_pci_get_log_pe(void)
{
return edac_pci_log_pe;
}
-int edac_pci_get_log_npe(void)
+static int edac_pci_get_log_npe(void)
{
return edac_pci_log_npe;
}
-int edac_pci_get_panic_on_pe(void)
+static int edac_pci_get_panic_on_pe(void)
{
return edac_pci_panic_on_pe;
}
@@ -197,7 +197,8 @@ error_out:
*
* unregister the kobj for the EDAC PCI instance
*/
-void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
+static void edac_pci_unregister_sysfs_instance_kobj(
+ struct edac_pci_ctl_info *pci)
{
debugf0("%s()\n", __func__);
@@ -337,7 +338,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = {
* setup the sysfs for EDAC PCI attributes
* assumes edac_class has already been initialized
*/
-int edac_pci_main_kobj_setup(void)
+static int edac_pci_main_kobj_setup(void)
{
int err;
struct sysdev_class *edac_class;
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 5d4292811c14..6c9a0f2a593c 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -326,15 +326,6 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
return -ENODEV;
}
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */
c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */
c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */
@@ -503,6 +494,10 @@ static int __init i3000_init(void)
int pci_rc;
debugf3("MC: %s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i3000_driver);
if (pci_rc < 0)
goto fail0;
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 5a852017c17a..4a16b5b61cfb 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -1286,16 +1286,6 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
if (PCI_FUNC(pdev->devfn) != 0)
return -ENODEV;
- /* make sure error reporting method is sane */
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
/* Ask the devices for the number of CSROWS and CHANNELS so
* that we can calculate the memory resources, etc
*
@@ -1478,6 +1468,9 @@ static int __init i5000_init(void)
debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i5000_driver);
return (pci_rc < 0) ? pci_rc : 0;
@@ -1501,5 +1494,6 @@ MODULE_AUTHOR
("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>");
MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
I5000_REVISION);
+
module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index 83bfe37c4bbb..c5305e3ee434 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82443_REVISION "0.1"
@@ -386,6 +387,9 @@ static struct pci_driver i82443bxgx_edacmc_driver = {
static int __init i82443bxgx_edacmc_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&i82443bxgx_edacmc_driver);
}
@@ -400,3 +404,6 @@ module_exit(i82443bxgx_edacmc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index f5ecd2c4d813..c0088ba9672b 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82860_REVISION " Ver: 2.0.2 " __DATE__
@@ -294,6 +295,9 @@ static int __init i82860_init(void)
debugf3("%s()\n", __func__);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
goto fail0;
@@ -345,3 +349,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
"Ben Woodard <woodard@redhat.com>");
MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 031abadc439a..e43bdc43a1bf 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82875P_REVISION " Ver: 2.0.2 " __DATE__
@@ -393,6 +394,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
struct i82875p_error_info discard;
debugf0("%s()\n", __func__);
+
ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
@@ -532,6 +534,10 @@ static int __init i82875p_init(void)
int pci_rc;
debugf3("%s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i82875p_driver);
if (pci_rc < 0)
@@ -586,3 +592,6 @@ module_exit(i82875p_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 0ee888456932..2eed3ea2cf62 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -14,7 +14,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-
+#include <linux/edac.h>
#include "edac_core.h"
#define I82975X_REVISION " Ver: 1.0.0 " __DATE__
@@ -611,6 +611,9 @@ static int __init i82975x_init(void)
debugf3("%s()\n", __func__);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i82975x_driver);
if (pci_rc < 0)
goto fail0;
@@ -664,3 +667,6 @@ module_exit(i82975x_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index 90320917be28..8e6b91bd2e99 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -26,6 +26,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define MODULE_NAME "pasemi_edac"
@@ -284,6 +285,9 @@ static struct pci_driver pasemi_edac_driver = {
static int __init pasemi_edac_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&pasemi_edac_driver);
}
@@ -298,3 +302,6 @@ module_exit(pasemi_edac_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index e25f712f2dc3..9900675e9598 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -20,6 +20,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define R82600_REVISION " Ver: 2.0.2 " __DATE__
@@ -393,6 +394,9 @@ static struct pci_driver r82600_driver = {
static int __init r82600_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&r82600_driver);
}
@@ -412,3 +416,6 @@ MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
module_param(disable_hardware_scrub, bool, 0644);
MODULE_PARM_DESC(disable_hardware_scrub,
"If set, disable the chipset's automatic scrub for CEs");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 2a999373863e..b2458bb8e9ca 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -784,7 +784,7 @@ static void sbp2_release_target(struct kref *kref)
kfree(lu);
}
scsi_remove_host(shost);
- fw_notify("released %s\n", tgt->bus_id);
+ fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no);
fw_unit_put(tgt->unit);
scsi_host_put(shost);
@@ -1487,7 +1487,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0)
goto out;
- memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+ memcpy(orb->request.command_block, cmd->cmnd, cmd->cmd_len);
orb->base.callback = complete_command_orb;
orb->base.request_bus =
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 40ffd767647d..dc2cec6127d1 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -17,6 +17,15 @@ config EDD
obscure configurations. Most disk controller BIOS vendors do
not yet implement this feature.
+config EDD_OFF
+ bool "Sets default behavior for EDD detection to off"
+ depends on EDD
+ default n
+ help
+ Say Y if you want EDD disabled by default, even though it is compiled into the
+ kernel. Say N if you want EDD enabled by default. EDD can be dynamically set
+ using the kernel parameter 'edd={on|skipmbr|off}'.
+
config EFI_VARS
tristate "EFI Variable Support via sysfs"
depends on EFI
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index f235940719e7..25918f7dfd0f 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -63,7 +63,7 @@ static void smi_data_buf_free(void)
return;
dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
- __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+ __func__, smi_data_buf_phys_addr, smi_data_buf_size);
dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
smi_data_buf_handle);
@@ -92,7 +92,7 @@ static int smi_data_buf_realloc(unsigned long size)
if (!buf) {
dev_dbg(&dcdbas_pdev->dev,
"%s: failed to allocate memory size %lu\n",
- __FUNCTION__, size);
+ __func__, size);
return -ENOMEM;
}
/* memory zeroed by dma_alloc_coherent */
@@ -110,7 +110,7 @@ static int smi_data_buf_realloc(unsigned long size)
smi_data_buf_size = size;
dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
- __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+ __func__, smi_data_buf_phys_addr, smi_data_buf_size);
return 0;
}
@@ -258,7 +258,7 @@ static int smi_request(struct smi_cmd *smi_cmd)
if (smi_cmd->magic != SMI_CMD_MAGIC) {
dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
- __FUNCTION__);
+ __func__);
return -EBADR;
}
@@ -267,7 +267,7 @@ static int smi_request(struct smi_cmd *smi_cmd)
set_cpus_allowed_ptr(current, &cpumask_of_cpu(0));
if (smp_processor_id() != 0) {
dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
- __FUNCTION__);
+ __func__);
ret = -EBUSY;
goto out;
}
@@ -428,7 +428,7 @@ static int host_control_smi(void)
default:
dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
- __FUNCTION__, host_control_smi_type);
+ __func__, host_control_smi_type);
return -ENOSYS;
}
@@ -456,13 +456,13 @@ static void dcdbas_host_control(void)
host_control_action = HC_ACTION_NONE;
if (!smi_data_buf) {
- dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__);
+ dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__);
return;
}
if (smi_data_buf_size < sizeof(struct apm_cmd)) {
dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
- __FUNCTION__);
+ __func__);
return;
}
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index 477a3d0e3caf..6a8b1e037e07 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -123,7 +123,7 @@ static int create_packet(void *data, size_t length)
if (!newpacket) {
printk(KERN_WARNING
"dell_rbu:%s: failed to allocate new "
- "packet\n", __FUNCTION__);
+ "packet\n", __func__);
retval = -ENOMEM;
spin_lock(&rbu_data.lock);
goto out_noalloc;
@@ -152,7 +152,7 @@ static int create_packet(void *data, size_t length)
printk(KERN_WARNING
"dell_rbu:%s: failed to allocate "
"invalid_addr_packet_array \n",
- __FUNCTION__);
+ __func__);
retval = -ENOMEM;
spin_lock(&rbu_data.lock);
goto out_alloc_packet;
@@ -164,7 +164,7 @@ static int create_packet(void *data, size_t length)
if (!packet_data_temp_buf) {
printk(KERN_WARNING
"dell_rbu:%s: failed to allocate new "
- "packet\n", __FUNCTION__);
+ "packet\n", __func__);
retval = -ENOMEM;
spin_lock(&rbu_data.lock);
goto out_alloc_packet_array;
@@ -416,7 +416,7 @@ static int img_update_realloc(unsigned long size)
*/
if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
printk(KERN_ERR "dell_rbu:%s: corruption "
- "check failed\n", __FUNCTION__);
+ "check failed\n", __func__);
return -EINVAL;
}
/*
@@ -642,7 +642,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj,
if (req_firm_rc) {
printk(KERN_ERR
"dell_rbu:%s request_firmware_nowait"
- " failed %d\n", __FUNCTION__, rc);
+ " failed %d\n", __func__, rc);
rc = -EIO;
} else
rbu_data.entry_created = 1;
@@ -718,7 +718,7 @@ static int __init dcdrbu_init(void)
if (IS_ERR(rbu_device)) {
printk(KERN_ERR
"dell_rbu:%s:platform_device_register_simple "
- "failed\n", __FUNCTION__);
+ "failed\n", __func__);
return PTR_ERR(rbu_device);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 24c62b848bf9..7f138c6195ff 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -382,7 +382,7 @@ fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
pr_debug("%s: gpio-%d status %d\n",
- __FUNCTION__, gpio, status);
+ __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_direction_input);
@@ -420,7 +420,7 @@ fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
pr_debug("%s: gpio-%d status %d\n",
- __FUNCTION__, gpio, status);
+ __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_direction_output);
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index e0e0af536108..93f916720b13 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -23,21 +23,19 @@
#define PCA953X_INVERT 2
#define PCA953X_DIRECTION 3
-/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
-struct pca953x_desc {
- char name[I2C_NAME_SIZE];
- unsigned long driver_data;
-};
-
-static const struct pca953x_desc pca953x_descs[] = {
+static const struct i2c_device_id pca953x_id[] = {
{ "pca9534", 8, },
{ "pca9535", 16, },
{ "pca9536", 4, },
{ "pca9537", 4, },
{ "pca9538", 8, },
{ "pca9539", 16, },
+ { "pca9555", 16, },
+ { "pca9557", 8, },
/* REVISIT several pca955x parts should work here too */
+ { }
};
+MODULE_DEVICE_TABLE(i2c, pca953x_id);
struct pca953x_chip {
unsigned gpio_start;
@@ -192,26 +190,17 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->owner = THIS_MODULE;
}
-static int __devinit pca953x_probe(struct i2c_client *client)
+static int __devinit pca953x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
- int ret, i;
- const struct pca953x_desc *id = NULL;
+ int ret;
pdata = client->dev.platform_data;
if (pdata == NULL)
return -ENODEV;
- /* this loop vanishes when we get i2c_device_id */
- for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
- if (!strcmp(pca953x_descs[i].name, client->name)) {
- id = pca953x_descs + i;
- break;
- }
- if (!id)
- return -ENODEV;
-
chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
@@ -291,6 +280,7 @@ static struct i2c_driver pca953x_driver = {
},
.probe = pca953x_probe,
.remove = pca953x_remove,
+ .id_table = pca953x_id,
};
static int __init pca953x_init(void)
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
index 1106aa15ac79..aa6cc8b2a2bc 100644
--- a/drivers/gpio/pcf857x.c
+++ b/drivers/gpio/pcf857x.c
@@ -26,6 +26,21 @@
#include <asm/gpio.h>
+static const struct i2c_device_id pcf857x_id[] = {
+ { "pcf8574", 8 },
+ { "pca8574", 8 },
+ { "pca9670", 8 },
+ { "pca9672", 8 },
+ { "pca9674", 8 },
+ { "pcf8575", 16 },
+ { "pca8575", 16 },
+ { "pca9671", 16 },
+ { "pca9673", 16 },
+ { "pca9675", 16 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf857x_id);
+
/*
* The pcf857x, pca857x, and pca967x chips only expose one read and one
* write register. Writing a "one" bit (to match the reset state) lets
@@ -142,7 +157,8 @@ static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value)
/*-------------------------------------------------------------------------*/
-static int pcf857x_probe(struct i2c_client *client)
+static int pcf857x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct pcf857x_platform_data *pdata;
struct pcf857x *gpio;
@@ -172,13 +188,8 @@ static int pcf857x_probe(struct i2c_client *client)
*
* NOTE: we don't distinguish here between *4 and *4a parts.
*/
- if (strcmp(client->name, "pcf8574") == 0
- || strcmp(client->name, "pca8574") == 0
- || strcmp(client->name, "pca9670") == 0
- || strcmp(client->name, "pca9672") == 0
- || strcmp(client->name, "pca9674") == 0
- ) {
- gpio->chip.ngpio = 8;
+ gpio->chip.ngpio = id->driver_data;
+ if (gpio->chip.ngpio == 8) {
gpio->chip.direction_input = pcf857x_input8;
gpio->chip.get = pcf857x_get8;
gpio->chip.direction_output = pcf857x_output8;
@@ -198,13 +209,7 @@ static int pcf857x_probe(struct i2c_client *client)
*
* NOTE: we don't distinguish here between '75 and '75c parts.
*/
- } else if (strcmp(client->name, "pcf8575") == 0
- || strcmp(client->name, "pca8575") == 0
- || strcmp(client->name, "pca9671") == 0
- || strcmp(client->name, "pca9673") == 0
- || strcmp(client->name, "pca9675") == 0
- ) {
- gpio->chip.ngpio = 16;
+ } else if (gpio->chip.ngpio == 16) {
gpio->chip.direction_input = pcf857x_input16;
gpio->chip.get = pcf857x_get16;
gpio->chip.direction_output = pcf857x_output16;
@@ -313,6 +318,7 @@ static struct i2c_driver pcf857x_driver = {
},
.probe = pcf857x_probe,
.remove = pcf857x_remove,
+ .id_table = pcf857x_id,
};
static int __init pcf857x_init(void)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index e03c67dd3e63..f43d6d3cf2fa 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -606,7 +606,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
case 2:
if ((end - start) < 2)
return NULL;
- item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
+ item->data.u16 = get_unaligned_le16(start);
start = (__u8 *)((__le16 *)start + 1);
return start;
@@ -614,7 +614,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
item->size++;
if ((end - start) < 4)
return NULL;
- item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
+ item->data.u32 = get_unaligned_le32(start);
start = (__u8 *)((__le32 *)start + 1);
return start;
}
@@ -765,7 +765,7 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
report += offset >> 3; /* adjust byte index */
offset &= 7; /* now only need bit offset into one byte */
- x = le64_to_cpu(get_unaligned((__le64 *) report));
+ x = get_unaligned_le64(report);
x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
return (u32) x;
}
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index ed71a8bc70dc..5c8b6e0ff47c 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -224,7 +224,7 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
if (in_data & 0xF000) {
printk(KERN_DEBUG
"%s : Doesn't look like an ads7828 device\n",
- __FUNCTION__);
+ __func__);
goto exit_free;
}
}
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index 9587869bdba0..c1009d6f9796 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -422,18 +422,14 @@ static ssize_t show_volt(struct device *dev, struct device_attribute *devattr,
* number in the range -128 to 127, or as an unsigned number that must
* be offset by 64.
*/
-static int decode_temp(struct adt7473_data *data, u8 raw)
+static int decode_temp(u8 twos_complement, u8 raw)
{
- if (data->temp_twos_complement)
- return (s8)raw;
- return raw - 64;
+ return twos_complement ? (s8)raw : raw - 64;
}
-static u8 encode_temp(struct adt7473_data *data, int cooked)
+static u8 encode_temp(u8 twos_complement, int cooked)
{
- if (data->temp_twos_complement)
- return (cooked & 0xFF);
- return cooked + 64;
+ return twos_complement ? cooked & 0xFF : cooked + 64;
}
static ssize_t show_temp_min(struct device *dev,
@@ -442,8 +438,9 @@ static ssize_t show_temp_min(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_min[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_min[attr->index]));
}
static ssize_t set_temp_min(struct device *dev,
@@ -455,7 +452,7 @@ static ssize_t set_temp_min(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_min[attr->index] = temp;
@@ -472,8 +469,9 @@ static ssize_t show_temp_max(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_max[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_max[attr->index]));
}
static ssize_t set_temp_max(struct device *dev,
@@ -485,7 +483,7 @@ static ssize_t set_temp_max(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_max[attr->index] = temp;
@@ -501,8 +499,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp[attr->index]));
}
static ssize_t show_fan_min(struct device *dev,
@@ -671,8 +670,9 @@ static ssize_t show_temp_tmax(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_tmax[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_tmax[attr->index]));
}
static ssize_t set_temp_tmax(struct device *dev,
@@ -684,7 +684,7 @@ static ssize_t set_temp_tmax(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_tmax[attr->index] = temp;
@@ -701,8 +701,9 @@ static ssize_t show_temp_tmin(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_tmin[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_tmin[attr->index]));
}
static ssize_t set_temp_tmin(struct device *dev,
@@ -714,7 +715,7 @@ static ssize_t set_temp_tmin(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 84712a22acea..fe2eea4d799b 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -953,12 +953,8 @@ static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
static void asb100_init_client(struct i2c_client *client)
{
struct asb100_data *data = i2c_get_clientdata(client);
- int vid = 0;
- vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
- vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
data->vrm = vid_which_vrm();
- vid = vid_from_reg(vid, data->vrm);
/* Start monitoring */
asb100_write_value(client, ASB100_REG_CONFIG,
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 1464338e4e11..dc1f30e432ea 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -117,7 +117,8 @@ struct f75375_data {
static int f75375_attach_adapter(struct i2c_adapter *adapter);
static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
static int f75375_detach_client(struct i2c_client *client);
-static int f75375_probe(struct i2c_client *client);
+static int f75375_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
static int f75375_remove(struct i2c_client *client);
static struct i2c_driver f75375_legacy_driver = {
@@ -128,12 +129,20 @@ static struct i2c_driver f75375_legacy_driver = {
.detach_client = f75375_detach_client,
};
+static const struct i2c_device_id f75375_id[] = {
+ { "f75373", f75373 },
+ { "f75375", f75375 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, f75375_id);
+
static struct i2c_driver f75375_driver = {
.driver = {
.name = "f75375",
},
.probe = f75375_probe,
.remove = f75375_remove,
+ .id_table = f75375_id,
};
static inline int f75375_read8(struct i2c_client *client, u8 reg)
@@ -628,7 +637,8 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
}
-static int f75375_probe(struct i2c_client *client)
+static int f75375_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct f75375_data *data = i2c_get_clientdata(client);
struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
@@ -643,15 +653,7 @@ static int f75375_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
data->client = client;
mutex_init(&data->update_lock);
-
- if (strcmp(client->name, "f75375") == 0)
- data->kind = f75375;
- else if (strcmp(client->name, "f75373") == 0)
- data->kind = f75373;
- else {
- dev_err(&client->dev, "Unsupported device: %s\n", client->name);
- return -ENODEV;
- }
+ data->kind = id->driver_data;
if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
goto exit_free;
@@ -712,6 +714,7 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
u8 version = 0;
int err = 0;
const char *name = "";
+ struct i2c_device_id id;
if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
err = -ENOMEM;
@@ -748,7 +751,9 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = i2c_attach_client(client)))
goto exit_free;
- if ((err = f75375_probe(client)) < 0)
+ strlcpy(id.name, name, I2C_NAME_SIZE);
+ id.driver_data = kind;
+ if ((err = f75375_probe(client, &id)) < 0)
goto exit_detach;
return 0;
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 115f4090b98e..fa7696905154 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -248,7 +248,7 @@ static int lm75_detach_client(struct i2c_client *client)
/* All registers are word-sized, except for the configuration register.
LM75 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
+ the SMBus standard. */
static int lm75_read_value(struct i2c_client *client, u8 reg)
{
if (reg == LM75_REG_CONF)
@@ -257,9 +257,6 @@ static int lm75_read_value(struct i2c_client *client, u8 reg)
return swab16(i2c_smbus_read_word_data(client, reg));
}
-/* All registers are word-sized, except for the configuration register.
- LM75 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == LM75_REG_CONF)
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index f61d8f4185b2..eb03544c731c 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -335,11 +335,23 @@ exit:
static int __init smsc47b397_find(unsigned short *addr)
{
u8 id, rev;
+ char *name;
superio_enter();
id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
- if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
+ switch(id) {
+ case 0x81:
+ name = "SCH5307-NS";
+ break;
+ case 0x6f:
+ name = "LPC47B397-NC";
+ break;
+ case 0x85:
+ case 0x8c:
+ name = "SCH5317";
+ break;
+ default:
superio_exit();
return -ENODEV;
}
@@ -352,8 +364,7 @@ static int __init smsc47b397_find(unsigned short *addr)
printk(KERN_INFO DRVNAME ": found SMSC %s "
"(base address 0x%04x, revision %u)\n",
- id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
- "LPC47B397-NC", *addr, rev);
+ name, *addr, rev);
superio_exit();
return 0;
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index ee35af93b574..ed3c019b78c7 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -1024,10 +1024,9 @@ static struct sensor_device_attribute_2 w83793_vid[] = {
SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
};
+static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
static struct sensor_device_attribute_2 sda_single_files[] = {
- SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm,
- NOT_USED, NOT_USED),
SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 30),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
@@ -1080,6 +1079,7 @@ static int w83793_detach_client(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
device_remove_file(dev, &w83793_vid[i].dev_attr);
+ device_remove_file(dev, &dev_attr_vrm);
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
device_remove_file(dev, &w83793_left_fan[i].dev_attr);
@@ -1282,7 +1282,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
/* Initialize the chip */
w83793_init_client(client);
- data->vrm = vid_which_vrm();
/*
Only fan 1-5 has their own input pins,
Pwm 1-3 has their own pins
@@ -1293,7 +1292,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
/* check the function of pins 49-56 */
- if (!(tmp & 0x80)) {
+ if (tmp & 0x80) {
+ data->has_vid |= 0x2; /* has VIDB */
+ } else {
data->has_pwm |= 0x18; /* pwm 4,5 */
if (val & 0x01) { /* fan 6 */
data->has_fan |= 0x20;
@@ -1309,13 +1310,15 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
+ /* check the function of pins 37-40 */
+ if (!(tmp & 0x29))
+ data->has_vid |= 0x1; /* has VIDA */
if (0x08 == (tmp & 0x0c)) {
if (val & 0x08) /* fan 9 */
data->has_fan |= 0x100;
if (val & 0x10) /* fan 10 */
data->has_fan |= 0x200;
}
-
if (0x20 == (tmp & 0x30)) {
if (val & 0x20) /* fan 11 */
data->has_fan |= 0x400;
@@ -1359,13 +1362,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
if (tmp & 0x02)
data->has_temp |= 0x20;
- /* Detect the VID usage and ignore unused input */
- tmp = w83793_read_value(client, W83793_REG_MFC);
- if (!(tmp & 0x29))
- data->has_vid |= 0x1; /* has VIDA */
- if (tmp & 0x80)
- data->has_vid |= 0x2; /* has VIDB */
-
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
err = device_create_file(dev,
@@ -1381,6 +1377,12 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
if (err)
goto exit_remove;
}
+ if (data->has_vid) {
+ data->vrm = vid_which_vrm();
+ err = device_create_file(dev, &dev_attr_vrm);
+ if (err)
+ goto exit_remove;
+ }
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
err = device_create_file(dev, &sda_single_files[i].dev_attr);
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 77f2d482888b..52e268e25dab 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -301,8 +301,8 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
msleep(i);
}
- dev_err(&client->dev, "Couldn't read value from register 0x%02x. "
- "Please report.\n", reg);
+ dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n",
+ reg);
return defval;
}
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
index e5e96c817566..c38a0a112208 100644
--- a/drivers/i2c/busses/i2c-amd756-s4882.c
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -1,7 +1,7 @@
/*
* i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
*
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004, 2008 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
@@ -231,7 +231,8 @@ ERROR2:
kfree(s4882_adapter);
s4882_adapter = NULL;
ERROR1:
- i2c_del_adapter(&amd756_smbus);
+ /* Restore physical bus */
+ i2c_add_adapter(&amd756_smbus);
ERROR0:
return error;
}
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 2fa43183d375..43508d61eb7c 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -290,7 +290,7 @@ static u32 amd756_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_DATA;
}
static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 491718fe46b7..cae9dc89d88c 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -335,7 +335,7 @@ i2c_au1550_probe(struct platform_device *pdev)
goto out_mem;
}
- priv->psc_base = r->start;
+ priv->psc_base = CKSEG1ADDR(r->start);
priv->xfer_timeout = 200;
priv->ack_timeout = 200;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 18beb0ad7bf3..a076129de7e8 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -99,7 +99,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
u32 x;
int result = 0;
- if (i2c->irq == 0)
+ if (i2c->irq == NO_IRQ)
{
while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
schedule();
@@ -329,10 +329,9 @@ static int fsl_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
i2c->irq = platform_get_irq(pdev, 0);
- if (i2c->irq < 0) {
- result = -ENXIO;
- goto fail_get_irq;
- }
+ if (i2c->irq < 0)
+ i2c->irq = NO_IRQ; /* Use polling */
+
i2c->flags = pdata->device_flags;
init_waitqueue_head(&i2c->queue);
@@ -344,7 +343,7 @@ static int fsl_i2c_probe(struct platform_device *pdev)
goto fail_map;
}
- if (i2c->irq != 0)
+ if (i2c->irq != NO_IRQ)
if ((result = request_irq(i2c->irq, mpc_i2c_isr,
IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
printk(KERN_ERR
@@ -367,12 +366,11 @@ static int fsl_i2c_probe(struct platform_device *pdev)
return result;
fail_add:
- if (i2c->irq != 0)
+ if (i2c->irq != NO_IRQ)
free_irq(i2c->irq, i2c);
fail_irq:
iounmap(i2c->base);
fail_map:
- fail_get_irq:
kfree(i2c);
return result;
};
@@ -384,7 +382,7 @@ static int fsl_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adap);
platform_set_drvdata(pdev, NULL);
- if (i2c->irq != 0)
+ if (i2c->irq != NO_IRQ)
free_irq(i2c->irq, i2c);
iounmap(i2c->base);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 3dac920e53ea..43c9f8df9509 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -50,6 +50,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
+#include <linux/dmi.h>
#include <asm/io.h>
MODULE_LICENSE("GPL");
@@ -109,6 +110,18 @@ struct nforce2_smbus {
/* Misc definitions */
#define MAX_TIMEOUT 100
+/* We disable the second SMBus channel on these boards */
+static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = {
+ {
+ .ident = "DFI Lanparty NF4 Expert",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"),
+ DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"),
+ },
+ },
+ { }
+};
+
static struct pci_driver nforce2_driver;
static void nforce2_abort(struct i2c_adapter *adap)
@@ -367,10 +380,17 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
smbuses[0].base = 0; /* to have a check value */
}
/* SMBus adapter 2 */
- res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
- if (res2 < 0) {
- dev_err(&dev->dev, "Error probing SMB2.\n");
- smbuses[1].base = 0; /* to have a check value */
+ if (dmi_check_system(nforce2_dmi_blacklist2)) {
+ dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n");
+ res2 = -EPERM;
+ smbuses[1].base = 0;
+ } else {
+ res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1],
+ "SMB2");
+ if (res2 < 0) {
+ dev_err(&dev->dev, "Error probing SMB2.\n");
+ smbuses[1].base = 0; /* to have a check value */
+ }
}
if ((res1 < 0) && (res2 < 0)) {
/* we did not find even one of the SMBuses, so we give up */
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 9bbe96cef719..ac9165968587 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -38,7 +38,6 @@
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <linux/apm_bios.h>
#include <linux/dmi.h>
#include <asm/io.h>
@@ -105,10 +104,31 @@ MODULE_PARM_DESC(force_addr,
static int piix4_transaction(void);
static unsigned short piix4_smba;
+static int srvrworks_csb5_delay;
static struct pci_driver piix4_driver;
static struct i2c_adapter piix4_adapter;
-static struct dmi_system_id __devinitdata piix4_dmi_table[] = {
+static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
+ {
+ .ident = "Sapphire AM2RD790",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "SAPPHIRE Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "PC-AM2RD790"),
+ },
+ },
+ {
+ .ident = "DFI Lanparty UT 790FX",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "DFI Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "LP UT 790FX"),
+ },
+ },
+ { }
+};
+
+/* The IBM entry is in a separate table because we only check it
+ on Intel-based systems */
+static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
{
.ident = "IBM",
.matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
@@ -123,8 +143,20 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
+ if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
+ (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
+ srvrworks_csb5_delay = 1;
+
+ /* On some motherboards, it was reported that accessing the SMBus
+ caused severe hardware problems */
+ if (dmi_check_system(piix4_dmi_blacklist)) {
+ dev_err(&PIIX4_dev->dev,
+ "Accessing the SMBus on this system is unsafe!\n");
+ return -EPERM;
+ }
+
/* Don't access SMBus on IBM systems which get corrupted eeproms */
- if (dmi_check_system(piix4_dmi_table) &&
+ if (dmi_check_system(piix4_dmi_ibm) &&
PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
dev_err(&PIIX4_dev->dev, "IBM system detected; this module "
"may corrupt your serial eeprom! Refusing to load "
@@ -223,7 +255,7 @@ static int piix4_transaction(void)
dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&piix4_adapter.dev, "Successfull!\n");
+ dev_dbg(&piix4_adapter.dev, "Successful!\n");
}
}
@@ -231,10 +263,14 @@ static int piix4_transaction(void)
outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
/* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
- do {
+ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */
+ msleep(2);
+ else
+ msleep(1);
+
+ while ((timeout++ < MAX_TIMEOUT) &&
+ ((temp = inb_p(SMBHSTSTS)) & 0x01))
msleep(1);
- temp = inb_p(SMBHSTSTS);
- } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
@@ -343,12 +379,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
switch (size) {
- case PIIX4_BYTE: /* Where is the result put? I assume here it is in
- SMBHSTDAT0 but it might just as well be in the
- SMBHSTCMD. No clue in the docs */
-
- data->byte = inb_p(SMBHSTDAT0);
- break;
+ case PIIX4_BYTE:
case PIIX4_BYTE_DATA:
data->byte = inb_p(SMBHSTDAT0);
break;
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
index 8fbbdb4c2f35..114634da6c6e 100644
--- a/drivers/i2c/busses/i2c-sibyte.c
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -132,14 +132,14 @@ static const struct i2c_algorithm i2c_sibyte_algo = {
/*
* registering functions to load algorithms at runtime
*/
-int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
{
struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
- /* register new adapter to i2c module... */
+ /* Register new adapter to i2c module... */
i2c_adap->algo = &i2c_sibyte_algo;
- /* Set the frequency to 100 kHz */
+ /* Set the requested frequency. */
csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 283769cecee2..9ca8f9155f95 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -238,7 +238,7 @@ static int sis5595_transaction(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&adap->dev, "Successfull!\n");
+ dev_dbg(&adap->dev, "Successful!\n");
}
}
@@ -316,14 +316,8 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
}
size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
break;
-/*
- case I2C_SMBUS_BLOCK_DATA:
- printk(KERN_WARNING "sis5595.o: Block data not yet implemented!\n");
- return -1;
- break;
-*/
default:
- printk(KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size);
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -1;
}
@@ -338,9 +332,7 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
switch (size) {
- case SIS5595_BYTE: /* Where is the result put? I assume here it is in
- SMB_DATA but it might just as well be in the
- SMB_CMD. No clue in the docs */
+ case SIS5595_BYTE:
case SIS5595_BYTE_DATA:
data->byte = sis5595_read(SMB_BYTE);
break;
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 5fd734f99ee9..3765dd7f450f 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -136,7 +136,7 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc
dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&adap->dev, "Successfull!\n");
+ dev_dbg(&adap->dev, "Successful!\n");
}
}
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index c2a9f8c94f5e..d08eeec53913 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -33,7 +33,7 @@
static unsigned short chip_addr[MAX_CHIPS];
module_param_array(chip_addr, ushort, NULL, S_IRUGO);
MODULE_PARM_DESC(chip_addr,
- "Chip addresses (up to 10, between 0x03 and 0x77)\n");
+ "Chip addresses (up to 10, between 0x03 and 0x77)");
struct stub_chip {
u8 pointer;
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
index 1b0cfd5472fd..de9db49e54d9 100644
--- a/drivers/i2c/busses/i2c-taos-evm.c
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -51,7 +51,6 @@ struct taos_data {
/* TAOS TSL2550 EVM */
static struct i2c_board_info tsl2550_info = {
I2C_BOARD_INFO("tsl2550", 0x39),
- .type = "tsl2550",
};
/* Instantiate i2c devices based on the adapter name */
@@ -59,7 +58,7 @@ static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
{
if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
- tsl2550_info.driver_name, tsl2550_info.addr);
+ tsl2550_info.type, tsl2550_info.addr);
return i2c_new_device(adapter, &tsl2550_info);
}
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
index 9e94542c18a2..23be4d42cb02 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/i2c/chips/ds1682.c
@@ -200,7 +200,8 @@ static struct bin_attribute ds1682_eeprom_attr = {
/*
* Called when a ds1682 device is matched with this driver
*/
-static int ds1682_probe(struct i2c_client *client)
+static int ds1682_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int rc;
@@ -234,12 +235,19 @@ static int ds1682_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id ds1682_id[] = {
+ { "ds1682", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1682_id);
+
static struct i2c_driver ds1682_driver = {
.driver = {
.name = "ds1682",
},
.probe = ds1682_probe,
.remove = ds1682_remove,
+ .id_table = ds1682_id,
};
static int __init ds1682_init(void)
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index fb7ea5637eca..cf507b3f60f3 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -207,9 +207,6 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
fake_client->flags = 0;
strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
- /* Prevent 24RF08 corruption (in case of user error) */
- i2c_smbus_write_quick(real_client, 0);
-
if ((err = i2c_attach_client(real_client)) != 0)
goto exit_kfree2;
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
index 2dea0123a958..b36db1797c11 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/i2c/chips/menelaus.c
@@ -1149,7 +1149,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m)
static struct i2c_driver menelaus_i2c_driver;
-static int menelaus_probe(struct i2c_client *client)
+static int menelaus_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct menelaus_chip *menelaus;
int rev = 0, val;
@@ -1242,12 +1243,19 @@ static int __exit menelaus_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id menelaus_id[] = {
+ { "menelaus", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, menelaus_id);
+
static struct i2c_driver menelaus_i2c_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = menelaus_probe,
.remove = __exit_p(menelaus_remove),
+ .id_table = menelaus_id,
};
static int __init menelaus_init(void)
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index b67f69c2e7f3..85949685191b 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -64,7 +64,6 @@ static struct i2c_driver tps65010_driver;
* as part of board setup by a bootloader.
*/
enum tps_model {
- TPS_UNKNOWN = 0,
TPS65010,
TPS65011,
TPS65012,
@@ -527,11 +526,13 @@ static int __exit tps65010_remove(struct i2c_client *client)
flush_scheduled_work();
debugfs_remove(tps->file);
kfree(tps);
+ i2c_set_clientdata(client, NULL);
the_tps = NULL;
return 0;
}
-static int tps65010_probe(struct i2c_client *client)
+static int tps65010_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tps65010 *tps;
int status;
@@ -552,20 +553,7 @@ static int tps65010_probe(struct i2c_client *client)
mutex_init(&tps->lock);
INIT_DELAYED_WORK(&tps->work, tps65010_work);
tps->client = client;
-
- if (strcmp(client->name, "tps65010") == 0)
- tps->model = TPS65010;
- else if (strcmp(client->name, "tps65011") == 0)
- tps->model = TPS65011;
- else if (strcmp(client->name, "tps65012") == 0)
- tps->model = TPS65012;
- else if (strcmp(client->name, "tps65013") == 0)
- tps->model = TPS65013;
- else {
- dev_warn(&client->dev, "unknown chip '%s'\n", client->name);
- status = -ENODEV;
- goto fail1;
- }
+ tps->model = id->driver_data;
/* the IRQ is active low, but many gpio lines can't support that
* so this driver uses falling-edge triggers instead.
@@ -594,9 +582,6 @@ static int tps65010_probe(struct i2c_client *client)
case TPS65012:
tps->por = 1;
break;
- case TPS_UNKNOWN:
- printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME);
- break;
/* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
}
tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG);
@@ -615,6 +600,7 @@ static int tps65010_probe(struct i2c_client *client)
i2c_smbus_read_byte_data(client, TPS_DEFGPIO),
i2c_smbus_read_byte_data(client, TPS_MASK3));
+ i2c_set_clientdata(client, tps);
the_tps = tps;
#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG)
@@ -682,12 +668,22 @@ fail1:
return status;
}
+static const struct i2c_device_id tps65010_id[] = {
+ { "tps65010", TPS65010 },
+ { "tps65011", TPS65011 },
+ { "tps65012", TPS65012 },
+ { "tps65013", TPS65013 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tps65010_id);
+
static struct i2c_driver tps65010_driver = {
.driver = {
.name = "tps65010",
},
.probe = tps65010_probe,
.remove = __exit_p(tps65010_remove),
+ .id_table = tps65010_id,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
index a10fd2791a69..1a9cc135219f 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/i2c/chips/tsl2550.c
@@ -364,7 +364,8 @@ static int tsl2550_init_client(struct i2c_client *client)
*/
static struct i2c_driver tsl2550_driver;
-static int __devinit tsl2550_probe(struct i2c_client *client)
+static int __devinit tsl2550_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct tsl2550_data *data;
@@ -451,6 +452,12 @@ static int tsl2550_resume(struct i2c_client *client)
#endif /* CONFIG_PM */
+static const struct i2c_device_id tsl2550_id[] = {
+ { "tsl2550", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tsl2550_id);
+
static struct i2c_driver tsl2550_driver = {
.driver = {
.name = TSL2550_DRV_NAME,
@@ -460,6 +467,7 @@ static struct i2c_driver tsl2550_driver = {
.resume = tsl2550_resume,
.probe = tsl2550_probe,
.remove = __devexit_p(tsl2550_remove),
+ .id_table = tsl2550_id,
};
static int __init tsl2550_init(void)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6c7fa8d53c0e..d0175f4f8fc6 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -48,6 +48,17 @@ static DEFINE_IDR(i2c_adapter_idr);
/* ------------------------------------------------------------------------- */
+static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+ const struct i2c_client *client)
+{
+ while (id->name[0]) {
+ if (strcmp(client->name, id->name) == 0)
+ return id;
+ id++;
+ }
+ return NULL;
+}
+
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -59,10 +70,11 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
if (!is_newstyle_driver(driver))
return 0;
- /* new style drivers use the same kind of driver matching policy
- * as platform devices or SPI: compare device and driver IDs.
- */
- return strcmp(client->driver_name, drv->name) == 0;
+ /* match on an id table if there is one */
+ if (driver->id_table)
+ return i2c_match_id(driver->id_table, client) != NULL;
+
+ return 0;
}
#ifdef CONFIG_HOTPLUG
@@ -73,10 +85,11 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
struct i2c_client *client = to_i2c_client(dev);
/* by definition, legacy drivers can't hotplug */
- if (dev->driver || !client->driver_name)
+ if (dev->driver)
return 0;
- if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
+ if (add_uevent_var(env, "MODALIAS=%s%s",
+ I2C_MODULE_PREFIX, client->name))
return -ENOMEM;
dev_dbg(dev, "uevent\n");
return 0;
@@ -90,13 +103,19 @@ static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver = to_i2c_driver(dev->driver);
+ const struct i2c_device_id *id;
int status;
if (!driver->probe)
return -ENODEV;
client->driver = driver;
dev_dbg(dev, "probe\n");
- status = driver->probe(client);
+
+ if (driver->id_table)
+ id = i2c_match_id(driver->id_table, client);
+ else
+ id = NULL;
+ status = driver->probe(client, id);
if (status)
client->driver = NULL;
return status;
@@ -179,9 +198,7 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
- return client->driver_name
- ? sprintf(buf, "%s\n", client->driver_name)
- : 0;
+ return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
}
static struct device_attribute i2c_dev_attrs[] = {
@@ -255,8 +272,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->addr = info->addr;
client->irq = info->irq;
- strlcpy(client->driver_name, info->driver_name,
- sizeof(client->driver_name));
strlcpy(client->name, info->type, sizeof(client->name));
/* a new style driver may be bound to this device when we
@@ -300,22 +315,33 @@ void i2c_unregister_device(struct i2c_client *client)
EXPORT_SYMBOL_GPL(i2c_unregister_device);
-static int dummy_nop(struct i2c_client *client)
+static const struct i2c_device_id dummy_id[] = {
+ { "dummy", 0 },
+ { },
+};
+
+static int dummy_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return 0;
+}
+
+static int dummy_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver dummy_driver = {
.driver.name = "dummy",
- .probe = dummy_nop,
- .remove = dummy_nop,
+ .probe = dummy_probe,
+ .remove = dummy_remove,
+ .id_table = dummy_id,
};
/**
* i2c_new_dummy - return a new i2c device bound to a dummy driver
* @adapter: the adapter managing the device
* @address: seven bit address to be used
- * @type: optional label used for i2c_client.name
* Context: can sleep
*
* This returns an I2C client bound to the "dummy" driver, intended for use
@@ -331,15 +357,12 @@ static struct i2c_driver dummy_driver = {
* i2c_unregister_device(); or NULL to indicate an error.
*/
struct i2c_client *
-i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type)
+i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
{
struct i2c_board_info info = {
- .driver_name = "dummy",
- .addr = address,
+ I2C_BOARD_INFO("dummy", address),
};
- if (type)
- strlcpy(info.type, type, sizeof info.type);
return i2c_new_device(adapter, &info);
}
EXPORT_SYMBOL_GPL(i2c_new_dummy);
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index f702f9152ce6..b4f3aefa12b6 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -1,8 +1,6 @@
#
# IDE ATA ATAPI Block device driver configuration
#
-# Andre Hedrick <andre@linux-ide.org>
-#
# Select HAVE_IDE if IDE is supported
config HAVE_IDE
@@ -335,7 +333,7 @@ config BLK_DEV_CMD640
This driver will work automatically in PCI based systems (most new
systems have PCI slots). But if your system uses VESA local bus
(VLB) instead of PCI, you must also supply a kernel boot parameter
- to enable the CMD640 bugfix/support: "ide0=cmd640_vlb". (Try "man
+ to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man
bootparam" or see the documentation of your boot loader about how to
pass options to the kernel.)
@@ -457,27 +455,11 @@ config BLK_DEV_ALI15X3
onboard chipsets. It also tests for Simplex mode and enables
normal dual channel support.
- If you say Y here, you also need to say Y to "Use DMA by default
- when available", above. Please read the comments at the top of
+ Please read the comments at the top of
<file:drivers/ide/pci/alim15x3.c>.
If unsure, say N.
-config WDC_ALI15X3
- bool "ALI M15x3 WDC support (DANGEROUS)"
- depends on BLK_DEV_ALI15X3
- ---help---
- This allows for UltraDMA support for WDC drives that ignore CRC
- checking. You are a fool for enabling this option, but there have
- been requests. DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORRUPTION, IF
- YOU ENABLE THIS! No one will listen, just laugh for ignoring this
- SERIOUS WARNING.
-
- Using this option can allow WDC drives to run at ATA-4/5 transfer
- rates with only an ATA-2 support structure.
-
- SAY N!
-
config BLK_DEV_AMD74XX
tristate "AMD and nVidia IDE support"
depends on !ARM
@@ -520,9 +502,6 @@ config BLK_DEV_CY82C693
This driver adds detection and support for the CY82C693 chipset
used on Digital's PC-Alpha 164SX boards.
- If you say Y here, you need to say Y to "Use DMA by default
- when available" as well.
-
config BLK_DEV_CS5520
tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -613,13 +592,12 @@ config BLK_DEV_SC1200
National SCx200 series of embedded x86 "Geode" systems.
config BLK_DEV_PIIX
- tristate "Intel PIIXn chipsets support"
+ tristate "Intel PIIX/ICH chipsets support"
select BLK_DEV_IDEDMA_PCI
help
- This driver adds explicit support for Intel PIIX and ICH chips
- and also for the Efar Victory66 (slc90e66) chip. This allows
- the kernel to change PIO, DMA and UDMA speeds and to configure
- the chip to optimum performance.
+ This driver adds explicit support for Intel PIIX and ICH chips.
+ This allows 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"
@@ -657,11 +635,7 @@ config BLK_DEV_PDC202XX_OLD
happen if the BIOS revisions of all installed cards (three-max) do
not match, the driver attempts to do dynamic tuning of the chipset
at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required
- for more than one card. This card may require that you say Y to
- "Special UDMA Feature".
-
- If you say Y here, you need to say Y to "Use DMA by default when
- available" as well.
+ for more than one card.
Please read the comments at the top of
<file:drivers/ide/pci/pdc202xx_old.c>.
@@ -710,9 +684,6 @@ config BLK_DEV_SIS5513
ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
SiS745, SiS750
- If you say Y here, you need to say Y to "Use DMA by default when
- available" as well.
-
Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
config BLK_DEV_SL82C105
@@ -734,9 +705,6 @@ config BLK_DEV_SLC90E66
and it will handle timing cycles. Since this is an improved
look-a-like to the PIIX4 it should be a nice addition.
- If you say Y here, you need to say Y to "Use DMA by default when
- available" as well.
-
Please read the comments at the top of
<file:drivers/ide/pci/slc90e66.c>.
@@ -888,17 +856,17 @@ config BLK_DEV_IDEDOUBLER
bool "Amiga IDE Doubler support (EXPERIMENTAL)"
depends on BLK_DEV_GAYLE && EXPERIMENTAL
---help---
- This driver provides support for the so-called `IDE doublers' (made
+ This feature provides support for the so-called `IDE doublers' (made
by various manufacturers, e.g. Eyetech) that can be connected to
the on-board IDE interface of some Amiga models. Using such an IDE
doubler, you can connect up to four instead of two IDE devices to
the Amiga's on-board IDE interface.
Note that the normal Amiga Gayle IDE driver may not work correctly
- if you have an IDE doubler and don't enable this driver!
+ if you have an IDE doubler and don't enable this feature!
- Say Y if you have an IDE doubler. The driver is enabled at kernel
- runtime using the "ide=doubler" kernel boot parameter.
+ Say Y if you have an IDE doubler. The feature is enabled at kernel
+ runtime using the "gayle.doubler" kernel boot parameter.
config BLK_DEV_BUDDHA
tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index fe9df38f62cc..68e7f19dc036 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -782,7 +782,7 @@ static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive)
sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
- memset(rq->cmd, 0, sizeof(rq->cmd));
+ memset(rq->cmd, 0, BLK_MAX_CDB);
rq->cmd[0] = GPCMD_SEEK;
put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
@@ -1694,7 +1694,7 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
long block = (long)rq->hard_sector / (hard_sect >> 9);
unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9);
- memset(rq->cmd, 0, sizeof(rq->cmd));
+ memset(rq->cmd, 0, BLK_MAX_CDB);
if (rq_data_dir(rq) == READ)
rq->cmd[0] = GPCMD_READ_10;
diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
index 6ed7ca071331..6490a2dea96b 100644
--- a/drivers/ide/ide-cd_verbose.c
+++ b/drivers/ide/ide-cd_verbose.c
@@ -326,7 +326,7 @@ void ide_cd_log_error(const char *name, struct request *failed_command,
printk(KERN_ERR " The failed \"%s\" packet command "
"was: \n \"", s);
- for (i = 0; i < sizeof(failed_command->cmd); i++)
+ for (i = 0; i < BLK_MAX_CDB; i++)
printk(KERN_CONT "%02x ", failed_command->cmd[i]);
printk(KERN_CONT "\"\n");
}
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 788783da9025..696525342e9a 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -1550,8 +1550,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
void ide_init_drive_cmd (struct request *rq)
{
- memset(rq, 0, sizeof(*rq));
- rq->ref_count = 1;
+ blk_rq_init(NULL, rq);
}
EXPORT_SYMBOL(ide_init_drive_cmd);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 57d9a9a79a6f..0daf923541ff 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -95,7 +95,7 @@ void SELECT_DRIVE (ide_drive_t *drive)
hwif->OUTB(drive->select.all, hwif->io_ports.device_addr);
}
-void SELECT_MASK (ide_drive_t *drive, int mask)
+static void SELECT_MASK(ide_drive_t *drive, int mask)
{
const struct ide_port_ops *port_ops = drive->hwif->port_ops;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 099a0fe1745b..34b0d4f26b58 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1347,19 +1347,14 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
(d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
hwif->irq = port ? 15 : 14;
- hwif->host_flags = d->host_flags;
+ /* ->host_flags may be set by ->init_iops (or even earlier...) */
+ hwif->host_flags |= d->host_flags;
hwif->pio_mask = d->pio_mask;
/* ->set_pio_mode for DTC2278 is currently limited to port 0 */
if (hwif->chipset != ide_dtc2278 || hwif->channel == 0)
hwif->port_ops = d->port_ops;
- if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
- ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) {
- if (hwif->mate)
- hwif->mate->serialized = hwif->serialized = 1;
- }
-
hwif->swdma_mask = d->swdma_mask;
hwif->mwdma_mask = d->mwdma_mask;
hwif->ultra_mask = d->udma_mask;
@@ -1381,6 +1376,12 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
hwif->dma_ops = d->dma_ops;
}
+ if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
+ ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) {
+ if (hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
+ }
+
if (d->host_flags & IDE_HFLAG_RQSIZE_256)
hwif->rqsize = 256;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 7b2f3815a838..8d6ad812a014 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -822,6 +822,7 @@ static int ide_drivers_open(struct inode *inode, struct file *file)
}
static const struct file_operations ide_drivers_operations = {
+ .owner = THIS_MODULE,
.open = ide_drivers_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -830,16 +831,12 @@ static const struct file_operations ide_drivers_operations = {
void proc_ide_create(void)
{
- struct proc_dir_entry *entry;
-
proc_ide_root = proc_mkdir("ide", NULL);
if (!proc_ide_root)
return;
- entry = create_proc_entry("drivers", 0, proc_ide_root);
- if (entry)
- entry->proc_fops = &ide_drivers_operations;
+ proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations);
}
void proc_ide_destroy(void)
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 54a43b044608..1e1f26331a24 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -662,7 +662,7 @@ static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
static void idetape_init_rq(struct request *rq, u8 cmd)
{
- memset(rq, 0, sizeof(*rq));
+ blk_rq_init(NULL, rq);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd[0] = cmd;
}
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 9a846a0cd5a4..0c908ca3ff79 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -494,8 +494,7 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
{
struct request rq;
- memset(&rq, 0, sizeof(rq));
- rq.ref_count = 1;
+ blk_rq_init(NULL, &rq);
rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
rq.buffer = buf;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 999584c03d97..c758dcb13b14 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -564,7 +564,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
if (!(drive->dn % 2))
ide_acpi_get_timing(hwif);
- memset(&rq, 0, sizeof(rq));
+ blk_rq_init(NULL, &rq);
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
rq.cmd_type = REQ_TYPE_PM_SUSPEND;
@@ -602,7 +602,7 @@ static int generic_ide_resume(struct device *dev)
ide_acpi_exec_tfs(drive);
- memset(&rq, 0, sizeof(rq));
+ blk_rq_init(NULL, &rq);
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
rq.cmd_type = REQ_TYPE_PM_RESUME;
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 83555ca513b5..9e449a0c623f 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -61,7 +61,7 @@ static void falconide_output_data(ide_drive_t *drive, struct request *rq,
unsigned long data_addr = drive->hwif->io_ports.data_addr;
if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
- return outsw(data_adr, buf, (len + 1) / 2);
+ return outsw(data_addr, buf, (len + 1) / 2);
outsw_swapw(data_addr, buf, (len + 1) / 2);
}
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index 1f527bbf8d96..caa2632dd08e 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -95,6 +95,9 @@ static int __init macide_init(void)
int irq;
hw_regs_t hw;
+ if (!MACH_IS_MAC)
+ return -ENODEV;
+
switch (macintosh_config->ide_type) {
case MAC_IDE_QUADRA:
base = IDE_BASE;
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 712d17bdd470..52fee3d2771a 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -4,7 +4,7 @@
* Author: Manish Lachwani, mlachwani@mvista.com
* Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
* Author: Maciej W. Rozycki <macro@mips.com>
- * Copyright (c) 2006 Maciej W. Rozycki
+ * Copyright (c) 2006, 2008 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -70,8 +70,9 @@ static int __devinit swarm_ide_probe(struct device *dev)
ide_hwif_t *hwif;
u8 __iomem *base;
phys_t offset, size;
+ hw_regs_t hw;
int i;
- u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ u8 idx[] = { 0xff, 0xff, 0xff, 0xff };
if (!SIBYTE_HAVE_IDE)
return -ENODEV;
@@ -112,14 +113,15 @@ static int __devinit swarm_ide_probe(struct device *dev)
hwif->host_flags = IDE_HFLAG_MMIO;
default_hwif_mmiops(hwif);
- hwif->chipset = ide_generic;
-
for (i = 0; i <= 7; i++)
- hwif->io_ports_array[i] =
+ hw.io_ports_array[i] =
(unsigned long)(base + ((0x1f0 + i) << 5));
- hwif->io_ports.ctl_addr =
+ hw.io_ports.ctl_addr =
(unsigned long)(base + (0x3f6 << 5));
- hwif->irq = K_INT_GB_IDE;
+ hw.irq = K_INT_GB_IDE;
+ hw.chipset = ide_generic;
+
+ ide_init_port_hw(hwif, &hw);
idx[0] = hwif->index;
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index b36a22b8c213..f2129d5e07f2 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -39,6 +39,16 @@
#include <asm/io.h>
/*
+ * Allow UDMA on M1543C-E chipset for WDC disks that ignore CRC checking
+ * (this is DANGEROUS and could result in data corruption).
+ */
+static int wdc_udma;
+
+module_param(wdc_udma, bool, 0);
+MODULE_PARM_DESC(wdc_udma,
+ "allow UDMA on M1543C-E chipset for WDC disks (DANGEROUS)");
+
+/*
* ALi devices are not plug in. Otherwise these static values would
* need to go. They ought to go away anyway
*/
@@ -76,11 +86,6 @@ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
a_clc = 0;
c_time = ide_pio_timings[pio].cycle_time;
-#if 0
- if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
- r_clc = 0;
-#endif
-
if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
r_clc = 1;
} else {
@@ -110,16 +115,6 @@ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_write_config_byte(dev, port, s_clc);
pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
local_irq_restore(flags);
-
- /*
- * setup active rec
- * { 70, 165, 365 }, PIO Mode 0
- * { 50, 125, 208 }, PIO Mode 1
- * { 30, 100, 110 }, PIO Mode 2
- * { 30, 80, 70 }, PIO Mode 3 with IORDY
- * { 25, 70, 25 }, PIO Mode 4 with IORDY ns
- * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
- */
}
/**
@@ -131,9 +126,7 @@ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
* The actual rules for the ALi are:
* No UDMA on revisions <= 0x20
* Disk only for revisions < 0xC2
- * Not WDC drives for revisions < 0xC2
- *
- * FIXME: WDC ifdef needs to die
+ * Not WDC drives on M1543C-E (?)
*/
static u8 ali_udma_filter(ide_drive_t *drive)
@@ -141,10 +134,9 @@ static u8 ali_udma_filter(ide_drive_t *drive)
if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
if (drive->media != ide_disk)
return 0;
-#ifndef CONFIG_WDC_ALI15X3
- if (chip_is_1543c_e && strstr(drive->id->model, "WDC "))
+ if (chip_is_1543c_e && strstr(drive->id->model, "WDC ") &&
+ wdc_udma == 0)
return 0;
-#endif
}
return drive->hwif->ultra_mask;
@@ -412,14 +404,14 @@ static u8 __devinit ali_cable_detect(ide_hwif_t *hwif)
return cbl;
}
-#ifndef CONFIG_SPARC64
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC)
/**
* init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff
* @hwif: interface to configure
*
* Obtain the IRQ tables for an ALi based IDE solution on the PC
* class platforms. This part of the code isn't applicable to the
- * Sparc systems
+ * Sparc and PowerPC systems.
*/
static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
@@ -463,7 +455,9 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
hwif->irq = irq;
}
}
-#endif
+#else
+#define init_hwif_ali15x3 NULL
+#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */
/**
* init_dma_ali15x3 - set up DMA on ALi15x3
@@ -517,9 +511,7 @@ static const struct ide_dma_ops ali_dma_ops = {
static const struct ide_port_info ali15x3_chipset __devinitdata = {
.name = "ALI15X3",
.init_chipset = init_chipset_ali15x3,
-#ifndef CONFIG_SPARC64
.init_hwif = init_hwif_ali15x3,
-#endif
.init_dma = init_dma_ali15x3,
.port_ops = &ali_port_ops,
.pio_mask = ATA_PIO5,
@@ -537,17 +529,9 @@ static const struct ide_port_info ali15x3_chipset __devinitdata = {
static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- static struct pci_device_id ati_rs100[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100) },
- { },
- };
-
struct ide_port_info d = ali15x3_chipset;
u8 rev = dev->revision, idx = id->driver_data;
- if (pci_dev_present(ati_rs100))
- printk(KERN_WARNING "alim15x3: ATI Radeon IGP Northbridge is not yet fully tested.\n");
-
/* don't use LBA48 DMA on ALi devices before rev 0xC5 */
if (rev <= 0xC4)
d.host_flags |= IDE_HFLAG_NO_LBA48_DMA;
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 17669a434438..992b1cf8db69 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -119,6 +119,7 @@ static const struct ide_dma_ops cs5520_dma_ops = {
.dma_timeout = ide_dma_timeout,
};
+/* FIXME: VDMA is disabled because it caused system hangs */
#define DECLARE_CS_DEV(name_str) \
{ \
.name = name_str, \
@@ -126,7 +127,6 @@ static const struct ide_dma_ops cs5520_dma_ops = {
.dma_ops = &cs5520_dma_ops, \
.host_flags = IDE_HFLAG_ISA_PORTS | \
IDE_HFLAG_CS5520 | \
- IDE_HFLAG_VDMA | \
IDE_HFLAG_NO_ATAPI_DMA | \
IDE_HFLAG_ABUSE_SET_DMA_MODE, \
.pio_mask = ATA_PIO4, \
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 4cf8fc54aa2a..0006b9e58567 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -737,8 +737,15 @@ static const struct ide_port_ops sil_sata_port_ops = {
.cable_detect = sil_cable_detect,
};
-static struct ide_dma_ops sil_dma_ops = {
+static const struct ide_dma_ops sil_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
.dma_test_irq = siimage_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
};
#define DECLARE_SII_DEV(name_str, p_ops) \
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 29d833e71cbf..05710c7c1220 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -520,8 +520,11 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
char *scratch = buf;
driver = container_of(drv, struct hpsb_protocol_driver, driver);
+ id = driver->id_table;
+ if (!id)
+ return 0;
- for (id = driver->id_table; id->match_flags != 0; id++) {
+ for (; id->match_flags != 0; id++) {
int need_coma = 0;
if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 4e3128ff73c1..fe78f7d25099 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -38,6 +38,7 @@
#include <linux/dma-mapping.h>
#include <linux/sched.h>
#include <linux/hugetlb.h>
+#include <linux/dma-attrs.h>
#include "uverbs.h"
@@ -72,9 +73,10 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
* @addr: userspace virtual address to start at
* @size: length of region to pin
* @access: IB_ACCESS_xxx flags for memory being pinned
+ * @dmasync: flush in-flight DMA when the memory region is written
*/
struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
- size_t size, int access)
+ size_t size, int access, int dmasync)
{
struct ib_umem *umem;
struct page **page_list;
@@ -87,6 +89,10 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
int ret;
int off;
int i;
+ DEFINE_DMA_ATTRS(attrs);
+
+ if (dmasync)
+ dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
if (!can_do_mlock())
return ERR_PTR(-EPERM);
@@ -174,10 +180,11 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0);
}
- chunk->nmap = ib_dma_map_sg(context->device,
- &chunk->page_list[0],
- chunk->nents,
- DMA_BIDIRECTIONAL);
+ chunk->nmap = ib_dma_map_sg_attrs(context->device,
+ &chunk->page_list[0],
+ chunk->nents,
+ DMA_BIDIRECTIONAL,
+ &attrs);
if (chunk->nmap <= 0) {
for (i = 0; i < chunk->nents; ++i)
put_page(sg_page(&chunk->page_list[i]));
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 6af2c0f79a67..2acf9b62cf99 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -452,7 +452,7 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
return ERR_PTR(-ENOMEM);
c2mr->pd = c2pd;
- c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+ c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(c2mr->umem)) {
err = PTR_ERR(c2mr->umem);
kfree(c2mr);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 66eb7030aea8..3f441fc57c17 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -359,9 +359,10 @@ static void insert_recv_cqe(struct t3_wq *wq, struct t3_cq *cq)
cq->sw_wptr++;
}
-void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
+int cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
{
u32 ptr;
+ int flushed = 0;
PDBG("%s wq %p cq %p\n", __func__, wq, cq);
@@ -369,8 +370,11 @@ void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
PDBG("%s rq_rptr %u rq_wptr %u skip count %u\n", __func__,
wq->rq_rptr, wq->rq_wptr, count);
ptr = wq->rq_rptr + count;
- while (ptr++ != wq->rq_wptr)
+ while (ptr++ != wq->rq_wptr) {
insert_recv_cqe(wq, cq);
+ flushed++;
+ }
+ return flushed;
}
static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq,
@@ -394,18 +398,21 @@ static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq,
cq->sw_wptr++;
}
-void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count)
+int cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count)
{
__u32 ptr;
+ int flushed = 0;
struct t3_swsq *sqp = wq->sq + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2);
ptr = wq->sq_rptr + count;
- sqp += count;
+ sqp = wq->sq + Q_PTR2IDX(ptr, wq->sq_size_log2);
while (ptr != wq->sq_wptr) {
insert_sq_cqe(wq, cq, sqp);
- sqp++;
ptr++;
+ sqp = wq->sq + Q_PTR2IDX(ptr, wq->sq_size_log2);
+ flushed++;
}
+ return flushed;
}
/*
@@ -456,7 +463,8 @@ void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count)
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)) &&
+ if ((SQ_TYPE(*cqe) ||
+ ((CQE_OPCODE(*cqe) == T3_READ_RESP) && wq->oldest_read)) &&
(CQE_QPID(*cqe) == wq->qpid))
(*count)++;
ptr++;
@@ -580,7 +588,7 @@ static int cxio_hal_destroy_ctrl_qp(struct cxio_rdev *rdev_p)
* 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 len, void *data)
{
u32 i, nr_wqe, copy_len;
u8 *copy_data;
@@ -616,7 +624,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
flag = 0;
if (i == (nr_wqe - 1)) {
/* last WQE */
- flag = completion ? T3_COMPLETION_FLAG : 0;
+ flag = T3_COMPLETION_FLAG;
if (len % 32)
utx_len = len / 32 + 1;
else
@@ -675,21 +683,20 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
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.
+/* IN: stag key, pdid, perm, zbva, to, len, page_size, pbl_size and pbl_addr
+ * OUT: stag index
* 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)
+ u32 zbva, u64 to, u32 len, u8 page_size,
+ 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;
@@ -703,30 +710,8 @@ static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
PDBG("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
__func__, 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",
- __func__, *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));
@@ -741,23 +726,23 @@ static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
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));
+ 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));
+ 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);
+ sizeof(tpt), &tpt);
/* 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)
@@ -768,44 +753,67 @@ ret:
return err;
}
+int cxio_write_pbl(struct cxio_rdev *rdev_p, __be64 *pbl,
+ u32 pbl_addr, u32 pbl_size)
+{
+ u32 wptr;
+ int err;
+
+ PDBG("%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
+ __func__, pbl_addr, rdev_p->rnic_info.pbl_base,
+ pbl_size);
+
+ mutex_lock(&rdev_p->ctrl_qp.lock);
+ err = cxio_hal_ctrl_qp_write_mem(rdev_p, pbl_addr >> 5, pbl_size << 3,
+ pbl);
+ wptr = rdev_p->ctrl_qp.wptr;
+ mutex_unlock(&rdev_p->ctrl_qp.lock);
+ if (err)
+ return err;
+
+ if (wait_event_interruptible(rdev_p->ctrl_qp.waitq,
+ SEQ32_GE(rdev_p->ctrl_qp.rptr,
+ wptr)))
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
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)
+ u8 page_size, 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);
+ zbva, to, len, page_size, 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)
+ u8 page_size, 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);
+ zbva, to, len, page_size, 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);
+ return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0,
+ 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);
+ 0, 0);
}
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);
+ return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0,
+ 0, 0);
}
int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr)
@@ -829,7 +837,8 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr)
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->rqe_count = cpu_to_be16(attr->rqe_count);
+ wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type));
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);
@@ -1135,6 +1144,18 @@ int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe,
if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) {
/*
+ * If this is an unsolicited read response, then the read
+ * was generated by the kernel driver as part of peer-2-peer
+ * connection setup. So ignore the completion.
+ */
+ if (!wq->oldest_read) {
+ if (CQE_STATUS(*hw_cqe))
+ wq->error = 1;
+ ret = -1;
+ goto skip_cqe;
+ }
+
+ /*
* Don't write to the HWCQ, so create a new read req CQE
* in local memory.
*/
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index 99543d634704..6e128f6bab05 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -53,6 +53,7 @@
#define T3_MAX_PBL_SIZE 256
#define T3_MAX_RQ_SIZE 1024
#define T3_MAX_NUM_STAG (1<<15)
+#define T3_MAX_MR_SIZE 0x100000000ULL
#define T3_STAG_UNSET 0xffffffff
@@ -153,14 +154,14 @@ int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq,
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_write_pbl(struct cxio_rdev *rdev_p, __be64 *pbl,
+ u32 pbl_addr, u32 pbl_size);
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);
+ u8 page_size, 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);
+ u8 page_size, 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);
@@ -172,8 +173,8 @@ 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);
+int cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count);
+int 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);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c
index 45ed4f25ef78..bd233c087653 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_resource.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c
@@ -250,7 +250,6 @@ void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
*/
#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)
{
@@ -267,14 +266,35 @@ void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
{
- unsigned long i;
+ unsigned pbl_start, pbl_chunk;
+
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;
+ if (!rdev_p->pbl_pool)
+ return -ENOMEM;
+
+ pbl_start = rdev_p->rnic_info.pbl_base;
+ pbl_chunk = rdev_p->rnic_info.pbl_top - pbl_start + 1;
+
+ while (pbl_start < rdev_p->rnic_info.pbl_top) {
+ pbl_chunk = min(rdev_p->rnic_info.pbl_top - pbl_start + 1,
+ pbl_chunk);
+ if (gen_pool_add(rdev_p->pbl_pool, pbl_start, pbl_chunk, -1)) {
+ PDBG("%s failed to add PBL chunk (%x/%x)\n",
+ __func__, pbl_start, pbl_chunk);
+ if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
+ printk(KERN_WARNING MOD "%s: Failed to add all PBL chunks (%x/%x)\n",
+ __func__, pbl_start, rdev_p->rnic_info.pbl_top - pbl_start);
+ return 0;
+ }
+ pbl_chunk >>= 1;
+ } else {
+ PDBG("%s added PBL chunk (%x/%x)\n",
+ __func__, pbl_start, pbl_chunk);
+ pbl_start += pbl_chunk;
+ }
+ }
+
+ return 0;
}
void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index 969d4d928455..f1a25a821a45 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -278,6 +278,17 @@ enum t3_qp_caps {
uP_RI_QP_STAG0_ENABLE = 0x10
} __attribute__ ((packed));
+enum rdma_init_rtr_types {
+ RTR_READ = 1,
+ RTR_WRITE = 2,
+ RTR_SEND = 3,
+};
+
+#define S_RTR_TYPE 2
+#define M_RTR_TYPE 0x3
+#define V_RTR_TYPE(x) ((x) << S_RTR_TYPE)
+#define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE)
+
struct t3_rdma_init_attr {
u32 tid;
u32 qpid;
@@ -293,7 +304,9 @@ struct t3_rdma_init_attr {
u32 ird;
u64 qp_dma_addr;
u32 qp_dma_size;
- u32 flags;
+ enum rdma_init_rtr_types rtr_type;
+ u16 flags;
+ u16 rqe_count;
u32 irs;
};
@@ -309,8 +322,8 @@ struct t3_rdma_init_wr {
u8 mpaattrs; /* 5 */
u8 qpcaps;
__be16 ulpdu_size;
- __be32 flags; /* bits 31-1 - reservered */
- /* bit 0 - set if RECV posted */
+ __be16 flags_rtr_type;
+ __be16 rqe_count;
__be32 ord; /* 6 */
__be32 ird;
__be64 qp_dma_addr; /* 7 */
@@ -324,7 +337,7 @@ struct t3_genbit {
};
enum rdma_init_wr_flags {
- RECVS_POSTED = (1<<0),
+ MPA_INITIATOR = (1<<0),
PRIV_QP = (1<<1),
};
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
index 6ba4138c8ec3..71554eacb13c 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.c
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -83,6 +83,7 @@ static void rnic_init(struct iwch_dev *rnicp)
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.max_mr_size = T3_MAX_MR_SIZE;
rnicp->attr.can_resize_wq = 0;
rnicp->attr.max_rdma_reads_per_qp = 8;
rnicp->attr.max_rdma_read_resources =
diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h
index 9ad9b1e7c8c1..d2409a505e8d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.h
+++ b/drivers/infiniband/hw/cxgb3/iwch.h
@@ -66,6 +66,7 @@ struct iwch_rnic_attributes {
* size (4k)^i. Phys block list mode unsupported.
*/
u32 mem_pgsizes_bitmask;
+ u64 max_mr_size;
u8 can_resize_wq;
/*
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 72ca360c3dbc..c325c44807e8 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -63,10 +63,14 @@ static char *states[] = {
NULL,
};
-static int ep_timeout_secs = 10;
+int peer2peer = 0;
+module_param(peer2peer, int, 0644);
+MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)");
+
+static int ep_timeout_secs = 60;
module_param(ep_timeout_secs, int, 0644);
MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
- "in seconds (default=10)");
+ "in seconds (default=60)");
static int mpa_rev = 1;
module_param(mpa_rev, int, 0644);
@@ -125,6 +129,12 @@ static void start_ep_timer(struct iwch_ep *ep)
static void stop_ep_timer(struct iwch_ep *ep)
{
PDBG("%s ep %p\n", __func__, ep);
+ if (!timer_pending(&ep->timer)) {
+ printk(KERN_ERR "%s timer stopped when its not running! ep %p state %u\n",
+ __func__, ep, ep->com.state);
+ WARN_ON(1);
+ return;
+ }
del_timer_sync(&ep->timer);
put_ep(&ep->com);
}
@@ -508,7 +518,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb)
skb_reset_transport_header(skb);
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_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL);
req->wr_lo = htonl(V_WR_TID(ep->hwtid));
req->len = htonl(len);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
@@ -559,7 +569,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen)
set_arp_failure_handler(skb, arp_failure_discard);
skb_reset_transport_header(skb);
req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
- req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL);
req->wr_lo = htonl(V_WR_TID(ep->hwtid));
req->len = htonl(mpalen);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
@@ -611,7 +621,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen)
skb_reset_transport_header(skb);
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_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL);
req->wr_lo = htonl(V_WR_TID(ep->hwtid));
req->len = htonl(len);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
@@ -879,6 +889,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb)
* the MPA header is valid.
*/
state_set(&ep->com, FPDU_MODE);
+ ep->mpa_attr.initiator = 1;
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;
@@ -901,8 +912,14 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb)
/* 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;
+ if (err)
+ goto err;
+
+ if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) {
+ iwch_post_zb_read(ep->com.qp);
+ }
+
+ goto out;
err:
abort_connection(ep, skb, GFP_KERNEL);
out:
@@ -995,6 +1012,7 @@ static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb)
* If we get here we have accumulated the entire mpa
* start reply message including private data.
*/
+ ep->mpa_attr.initiator = 0;
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;
@@ -1065,17 +1083,33 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
PDBG("%s ep %p credits %u\n", __func__, ep, credits);
- if (credits == 0)
+ if (credits == 0) {
+ PDBG(KERN_ERR "%s 0 credit ack ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
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) {
- ep->com.rpl_done = 1;
- PDBG("waking up ep %p\n", ep);
- wake_up(&ep->com.waitq);
+ if (!ep->mpa_skb) {
+ PDBG("%s rdma_init wr_ack ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
+ if (ep->mpa_attr.initiator) {
+ PDBG("%s initiator ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
+ if (peer2peer)
+ iwch_post_zb_read(ep->com.qp);
+ } else {
+ PDBG("%s responder ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
+ ep->com.rpl_done = 1;
+ wake_up(&ep->com.waitq);
+ }
+ } else {
+ PDBG("%s lsm ack ep %p state %u freeing skb\n",
+ __func__, ep, state_read(&ep->com));
+ kfree_skb(ep->mpa_skb);
+ ep->mpa_skb = NULL;
}
return CPL_RET_BUF_DONE;
}
@@ -1083,8 +1117,11 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
{
struct iwch_ep *ep = ctx;
+ unsigned long flags;
+ int release = 0;
PDBG("%s ep %p\n", __func__, ep);
+ BUG_ON(!ep);
/*
* We get 2 abort replies from the HW. The first one must
@@ -1095,9 +1132,22 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
return CPL_RET_BUF_DONE;
}
- close_complete_upcall(ep);
- state_set(&ep->com, DEAD);
- release_ep_resources(ep);
+ spin_lock_irqsave(&ep->com.lock, flags);
+ switch (ep->com.state) {
+ case ABORTING:
+ close_complete_upcall(ep);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ break;
+ default:
+ printk(KERN_ERR "%s ep %p state %d\n",
+ __func__, ep, ep->com.state);
+ break;
+ }
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+
+ if (release)
+ release_ep_resources(ep);
return CPL_RET_BUF_DONE;
}
@@ -1470,7 +1520,8 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
struct sk_buff *rpl_skb;
struct iwch_qp_attributes attrs;
int ret;
- int state;
+ int release = 0;
+ unsigned long flags;
if (is_neg_adv_abort(req->status)) {
PDBG("%s neg_adv_abort ep %p tid %d\n", __func__, ep,
@@ -1488,9 +1539,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
return CPL_RET_BUF_DONE;
}
- state = state_read(&ep->com);
- PDBG("%s ep %p state %u\n", __func__, ep, state);
- switch (state) {
+ spin_lock_irqsave(&ep->com.lock, flags);
+ PDBG("%s ep %p state %u\n", __func__, ep, ep->com.state);
+ switch (ep->com.state) {
case CONNECTING:
break;
case MPA_REQ_WAIT:
@@ -1536,21 +1587,25 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
break;
case DEAD:
PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
+ spin_unlock_irqrestore(&ep->com.lock, flags);
return CPL_RET_BUF_DONE;
default:
BUG_ON(1);
break;
}
dst_confirm(ep->dst);
+ if (ep->com.state != ABORTING) {
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ }
+ spin_unlock_irqrestore(&ep->com.lock, flags);
rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
if (!rpl_skb) {
printk(KERN_ERR MOD "%s - cannot allocate skb!\n",
__func__);
- dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
- put_ep(&ep->com);
- return CPL_RET_BUF_DONE;
+ release = 1;
+ goto out;
}
rpl_skb->priority = CPL_PRIORITY_DATA;
rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl));
@@ -1559,10 +1614,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid));
rpl->cmd = CPL_ABORT_NO_RST;
cxgb3_ofld_send(ep->com.tdev, rpl_skb);
- if (state != ABORTING) {
- state_set(&ep->com, DEAD);
+out:
+ if (release)
release_ep_resources(ep);
- }
return CPL_RET_BUF_DONE;
}
@@ -1596,8 +1650,8 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
release = 1;
break;
case ABORTING:
- break;
case DEAD:
+ break;
default:
BUG_ON(1);
break;
@@ -1661,15 +1715,18 @@ static void ep_timeout(unsigned long arg)
struct iwch_ep *ep = (struct iwch_ep *)arg;
struct iwch_qp_attributes attrs;
unsigned long flags;
+ int abort = 1;
spin_lock_irqsave(&ep->com.lock, flags);
PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
ep->com.state);
switch (ep->com.state) {
case MPA_REQ_SENT:
+ __state_set(&ep->com, ABORTING);
connect_reply_upcall(ep, -ETIMEDOUT);
break;
case MPA_REQ_WAIT:
+ __state_set(&ep->com, ABORTING);
break;
case CLOSING:
case MORIBUND:
@@ -1679,13 +1736,17 @@ static void ep_timeout(unsigned long arg)
ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
&attrs, 1);
}
+ __state_set(&ep->com, ABORTING);
break;
default:
- BUG();
+ printk(KERN_ERR "%s unexpected state ep %p state %u\n",
+ __func__, ep, ep->com.state);
+ WARN_ON(1);
+ abort = 0;
}
- __state_set(&ep->com, CLOSING);
spin_unlock_irqrestore(&ep->com.lock, flags);
- abort_connection(ep, NULL, GFP_ATOMIC);
+ if (abort)
+ abort_connection(ep, NULL, GFP_ATOMIC);
put_ep(&ep->com);
}
@@ -1762,16 +1823,19 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (err)
goto err;
+ /* if needed, wait for wr_ack */
+ if (iwch_rqes_posted(qp)) {
+ wait_event(ep->com.waitq, ep->com.rpl_done);
+ err = ep->com.rpl_err;
+ if (err)
+ goto err;
+ }
+
err = send_mpa_reply(ep, conn_param->private_data,
conn_param->private_data_len);
if (err)
goto err;
- /* wait for wr_ack */
- wait_event(ep->com.waitq, ep->com.rpl_done);
- err = ep->com.rpl_err;
- if (err)
- goto err;
state_set(&ep->com, FPDU_MODE);
established_upcall(ep);
@@ -1968,40 +2032,39 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp)
PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep,
states[ep->com.state], abrupt);
- if (ep->com.state == DEAD) {
- PDBG("%s already dead ep %p\n", __func__, 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:
- start_ep_timer(ep);
- ep->com.state = CLOSING;
close = 1;
+ if (abrupt)
+ ep->com.state = ABORTING;
+ else {
+ ep->com.state = CLOSING;
+ start_ep_timer(ep);
+ }
break;
case CLOSING:
- ep->com.state = MORIBUND;
close = 1;
+ if (abrupt) {
+ stop_ep_timer(ep);
+ ep->com.state = ABORTING;
+ } else
+ ep->com.state = MORIBUND;
break;
case MORIBUND:
+ case ABORTING:
+ case DEAD:
+ PDBG("%s ignoring disconnect ep %p state %u\n",
+ __func__, ep, ep->com.state);
break;
default:
BUG();
break;
}
-out:
+
spin_unlock_irqrestore(&ep->com.lock, flags);
if (close) {
if (abrupt)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
index 2bb7fbdb3ff4..d7c7e09f0996 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -56,6 +56,7 @@
#define put_ep(ep) { \
PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \
ep, atomic_read(&((ep)->kref.refcount))); \
+ WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \
kref_put(&((ep)->kref), __free_ep); \
}
@@ -225,5 +226,6 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, st
int __init iwch_cm_init(void);
void __exit iwch_cm_term(void);
+extern int peer2peer;
#endif /* _IWCH_CM_H_ */
diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
index 58c3d61bcd14..ec49a5cbdebb 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_mem.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
@@ -35,17 +35,26 @@
#include <rdma/ib_verbs.h>
#include "cxio_hal.h"
+#include "cxio_resource.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)
+static void iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag)
{
- u32 stag;
u32 mmid;
+ mhp->attr.state = 1;
+ mhp->attr.stag = stag;
+ mmid = stag >> 8;
+ mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
+ insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid);
+ PDBG("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp);
+}
+
+int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
+ struct iwch_mr *mhp, int shift)
+{
+ u32 stag;
if (cxio_register_phys_mem(&rhp->rdev,
&stag, mhp->attr.pdid,
@@ -53,28 +62,21 @@ int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
mhp->attr.zbva,
mhp->attr.va_fbo,
mhp->attr.len,
- shift-12,
- page_list,
- &mhp->attr.pbl_size, &mhp->attr.pbl_addr))
+ shift - 12,
+ 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", __func__, mmid, mhp);
+
+ iwch_finish_mem_reg(mhp, stag);
+
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)
@@ -87,19 +89,40 @@ int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
mhp->attr.zbva,
mhp->attr.va_fbo,
mhp->attr.len,
- shift-12,
- page_list,
- &mhp->attr.pbl_size, &mhp->attr.pbl_addr))
+ shift - 12,
+ 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", __func__, mmid, mhp);
+
+ iwch_finish_mem_reg(mhp, stag);
+
+ return 0;
+}
+
+int iwch_alloc_pbl(struct iwch_mr *mhp, int npages)
+{
+ mhp->attr.pbl_addr = cxio_hal_pblpool_alloc(&mhp->rhp->rdev,
+ npages << 3);
+
+ if (!mhp->attr.pbl_addr)
+ return -ENOMEM;
+
+ mhp->attr.pbl_size = npages;
+
return 0;
}
+void iwch_free_pbl(struct iwch_mr *mhp)
+{
+ cxio_hal_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
+ mhp->attr.pbl_size << 3);
+}
+
+int iwch_write_pbl(struct iwch_mr *mhp, __be64 *pages, int npages, int offset)
+{
+ return cxio_write_pbl(&mhp->rhp->rdev, pages,
+ mhp->attr.pbl_addr + (offset << 3), npages);
+}
+
int build_phys_page_list(struct ib_phys_buf *buffer_list,
int num_phys_buf,
u64 *iova_start,
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index ab4695c1dd56..8934178a23ee 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -442,6 +442,7 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr)
mmid = mhp->attr.stag >> 8;
cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr);
+ iwch_free_pbl(mhp);
remove_handle(rhp, &rhp->mmidr, mmid);
if (mhp->kva)
kfree((void *) (unsigned long) mhp->kva);
@@ -475,6 +476,8 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
if (!mhp)
return ERR_PTR(-ENOMEM);
+ mhp->rhp = rhp;
+
/* First check that we have enough alignment */
if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) {
ret = -EINVAL;
@@ -492,7 +495,17 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
if (ret)
goto err;
- mhp->rhp = rhp;
+ ret = iwch_alloc_pbl(mhp, npages);
+ if (ret) {
+ kfree(page_list);
+ goto err_pbl;
+ }
+
+ ret = iwch_write_pbl(mhp, page_list, npages, 0);
+ kfree(page_list);
+ if (ret)
+ goto err_pbl;
+
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
@@ -502,12 +515,15 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
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;
- }
+ ret = iwch_register_mem(rhp, php, mhp, shift);
+ if (ret)
+ goto err_pbl;
+
return &mhp->ibmr;
+
+err_pbl:
+ iwch_free_pbl(mhp);
+
err:
kfree(mhp);
return ERR_PTR(ret);
@@ -560,7 +576,7 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
return ret;
}
- ret = iwch_reregister_mem(rhp, php, &mh, shift, page_list, npages);
+ ret = iwch_reregister_mem(rhp, php, &mh, shift, npages);
kfree(page_list);
if (ret) {
return ret;
@@ -602,7 +618,9 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (!mhp)
return ERR_PTR(-ENOMEM);
- mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+ mhp->rhp = rhp;
+
+ mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(mhp->umem)) {
err = PTR_ERR(mhp->umem);
kfree(mhp);
@@ -615,10 +633,14 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
n += chunk->nents;
- pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
+ err = iwch_alloc_pbl(mhp, n);
+ if (err)
+ goto err;
+
+ pages = (__be64 *) __get_free_page(GFP_KERNEL);
if (!pages) {
err = -ENOMEM;
- goto err;
+ goto err_pbl;
}
i = n = 0;
@@ -630,25 +652,38 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
pages[i++] = cpu_to_be64(sg_dma_address(
&chunk->page_list[j]) +
mhp->umem->page_size * k);
+ if (i == PAGE_SIZE / sizeof *pages) {
+ err = iwch_write_pbl(mhp, pages, i, n);
+ if (err)
+ goto pbl_done;
+ n += i;
+ i = 0;
+ }
}
}
- mhp->rhp = rhp;
+ if (i)
+ err = iwch_write_pbl(mhp, pages, i, n);
+
+pbl_done:
+ free_page((unsigned long) pages);
+ if (err)
+ goto err_pbl;
+
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
mhp->attr.perms = iwch_ib_to_tpt_access(acc);
mhp->attr.va_fbo = virt;
mhp->attr.page_size = shift - 12;
mhp->attr.len = (u32) length;
- mhp->attr.pbl_size = i;
- err = iwch_register_mem(rhp, php, mhp, shift, pages);
- kfree(pages);
+
+ err = iwch_register_mem(rhp, php, mhp, shift);
if (err)
- goto err;
+ goto err_pbl;
if (udata && !t3a_device(rhp)) {
uresp.pbl_addr = (mhp->attr.pbl_addr -
- rhp->rdev.rnic_info.pbl_base) >> 3;
+ rhp->rdev.rnic_info.pbl_base) >> 3;
PDBG("%s user resp pbl_addr 0x%x\n", __func__,
uresp.pbl_addr);
@@ -661,6 +696,9 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
return &mhp->ibmr;
+err_pbl:
+ iwch_free_pbl(mhp);
+
err:
ib_umem_release(mhp->umem);
kfree(mhp);
@@ -998,7 +1036,7 @@ static int iwch_query_device(struct ib_device *ibdev,
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_mr_size = dev->attr.max_mr_size;
props->max_qp = dev->attr.max_qps;
props->max_qp_wr = dev->attr.max_wrs;
props->max_sge = dev->attr.max_sge_per_wr;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index 61356f91109d..836163fc5429 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -118,6 +118,7 @@ enum IWCH_QP_FLAGS {
};
struct iwch_mpa_attributes {
+ u8 initiator;
u8 recv_marker_enabled;
u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */
u8 crc_enabled;
@@ -322,6 +323,7 @@ enum iwch_qp_query_flags {
IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */
};
+u16 iwch_rqes_posted(struct iwch_qp *qhp);
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,
@@ -331,20 +333,21 @@ int iwch_bind_mw(struct ib_qp *qp,
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_post_zb_read(struct iwch_qp *qhp);
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);
+ struct iwch_mr *mhp, int shift);
int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
struct iwch_mr *mhp,
int shift,
- __be64 *page_list,
int npages);
+int iwch_alloc_pbl(struct iwch_mr *mhp, int npages);
+void iwch_free_pbl(struct iwch_mr *mhp);
+int iwch_write_pbl(struct iwch_mr *mhp, __be64 *pages, int npages, int offset);
int build_phys_page_list(struct ib_phys_buf *buffer_list,
int num_phys_buf,
u64 *iova_start,
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 8891c3b0a3d5..79dbe5beae52 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -586,6 +586,36 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg,
}
}
+int iwch_post_zb_read(struct iwch_qp *qhp)
+{
+ union t3_wr *wqe;
+ struct sk_buff *skb;
+ u8 flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3;
+
+ PDBG("%s enter\n", __func__);
+ skb = alloc_skb(40, GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR "%s cannot send zb_read!!\n", __func__);
+ return -ENOMEM;
+ }
+ wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr));
+ memset(wqe, 0, sizeof(struct t3_rdma_read_wr));
+ 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(1);
+ wqe->read.rem_to = cpu_to_be64(1);
+ wqe->read.local_stag = cpu_to_be32(1);
+ wqe->read.local_len = cpu_to_be32(0);
+ wqe->read.local_to = cpu_to_be64(1);
+ wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ));
+ wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)|
+ V_FW_RIWR_LEN(flit_cnt));
+ skb->priority = CPL_PRIORITY_DATA;
+ return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);
+}
+
/*
* This posts a TERMINATE with layer=RDMA, type=catastrophic.
*/
@@ -625,6 +655,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
{
struct iwch_cq *rchp, *schp;
int count;
+ int flushed;
rchp = get_chp(qhp->rhp, qhp->attr.rcq);
schp = get_chp(qhp->rhp, qhp->attr.scq);
@@ -639,20 +670,22 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *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);
+ flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&rchp->lock, *flag);
- (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+ if (flushed)
+ (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
/* 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);
+ flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&schp->lock, *flag);
- (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
+ if (flushed)
+ (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
/* deref */
if (atomic_dec_and_test(&qhp->refcnt))
@@ -671,11 +704,18 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
/*
- * Return non zero if at least one RECV was pre-posted.
+ * Return count of RECV WRs posted
*/
-static int rqes_posted(struct iwch_qp *qhp)
+u16 iwch_rqes_posted(struct iwch_qp *qhp)
{
- return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV;
+ union t3_wr *wqe = qhp->wq.queue;
+ u16 count = 0;
+ while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {
+ count++;
+ wqe++;
+ }
+ PDBG("%s qhp %p count %u\n", __func__, qhp, count);
+ return count;
}
static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
@@ -716,8 +756,17 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
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;
+ init_attr.rqe_count = iwch_rqes_posted(qhp);
+ init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0;
init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
+ if (peer2peer) {
+ init_attr.rtr_type = RTR_READ;
+ if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator)
+ init_attr.ord = 1;
+ if (init_attr.ird == 0 && !qhp->attr.mpa_attr.initiator)
+ init_attr.ird = 1;
+ } else
+ init_attr.rtr_type = 0;
init_attr.irs = qhp->ep->rcv_seq;
PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
"flags 0x%x qpcaps 0x%x\n", __func__,
@@ -832,8 +881,8 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
abort=0;
disconnect = 1;
ep = qhp->ep;
+ get_ep(&ep->com);
}
- flush_qp(qhp, &flag);
break;
case IWCH_QP_STATE_TERMINATE:
qhp->attr.state = IWCH_QP_STATE_TERMINATE;
@@ -848,6 +897,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
abort=1;
disconnect = 1;
ep = qhp->ep;
+ get_ep(&ep->com);
}
goto err;
break;
@@ -863,6 +913,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
}
switch (attrs->next_state) {
case IWCH_QP_STATE_IDLE:
+ flush_qp(qhp, &flag);
qhp->attr.state = IWCH_QP_STATE_IDLE;
qhp->attr.llp_stream_handle = NULL;
put_ep(&qhp->ep->com);
@@ -929,8 +980,10 @@ out:
* on the EP. This can be a normal close (RTS->CLOSING) or
* an abnormal close (RTS/CLOSING->ERROR).
*/
- if (disconnect)
+ if (disconnect) {
iwch_ep_disconnect(ep, abort, GFP_KERNEL);
+ put_ep(&ep->com);
+ }
/*
* If free is 1, then we've disassociated the EP from the QP
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 3d6d9461c31d..1e9e99a13933 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -66,6 +66,7 @@ struct ehca_av;
#include "ehca_irq.h"
#define EHCA_EQE_CACHE_SIZE 20
+#define EHCA_MAX_NUM_QUEUES 0xffff
struct ehca_eqe_cache_entry {
struct ehca_eqe *eqe;
@@ -127,6 +128,8 @@ struct ehca_shca {
/* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
u32 hca_cap_mr_pgsize;
int max_mtu;
+ atomic_t num_cqs;
+ atomic_t num_qps;
};
struct ehca_pd {
@@ -189,6 +192,8 @@ struct ehca_qp {
int mtu_shift;
u32 message_count;
u32 packet_count;
+ atomic_t nr_events; /* events seen */
+ wait_queue_head_t wait_completion;
};
#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
@@ -344,6 +349,8 @@ extern int ehca_use_hp_mr;
extern int ehca_scaling_code;
extern int ehca_lock_hcalls;
extern int ehca_nr_ports;
+extern int ehca_max_cq;
+extern int ehca_max_qp;
struct ipzu_queue_resp {
u32 qe_size; /* queue entry size */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index ec0cfcf3073f..5540b276a33c 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -132,10 +132,19 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
return ERR_PTR(-EINVAL);
+ if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) {
+ ehca_err(device, "Unable to create CQ, max number of %i "
+ "CQs reached.", ehca_max_cq);
+ ehca_err(device, "To increase the maximum number of CQs "
+ "use the number_of_cqs module parameter.\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
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);
+ atomic_dec(&shca->num_cqs);
return ERR_PTR(-ENOMEM);
}
@@ -305,6 +314,7 @@ create_cq_exit2:
create_cq_exit1:
kmem_cache_free(cq_cache, my_cq);
+ atomic_dec(&shca->num_cqs);
return cq;
}
@@ -359,6 +369,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
ipz_queue_dtor(NULL, &my_cq->ipz_queue);
kmem_cache_free(cq_cache, my_cq);
+ atomic_dec(&shca->num_cqs);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index b4ac617a70e6..49660dfa1867 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -54,7 +54,8 @@ int ehca_create_eq(struct ehca_shca *shca,
struct ehca_eq *eq,
const enum ehca_eq_type type, const u32 length)
{
- u64 ret;
+ int ret;
+ u64 h_ret;
u32 nr_pages;
u32 i;
void *vpage;
@@ -73,15 +74,15 @@ int ehca_create_eq(struct ehca_shca *shca,
return -EINVAL;
}
- ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
- &eq->pf,
- type,
- length,
- &eq->ipz_eq_handle,
- &eq->length,
- &nr_pages, &eq->ist);
+ h_ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
+ &eq->pf,
+ type,
+ length,
+ &eq->ipz_eq_handle,
+ &eq->length,
+ &nr_pages, &eq->ist);
- if (ret != H_SUCCESS) {
+ if (h_ret != H_SUCCESS) {
ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq);
return -EINVAL;
}
@@ -97,24 +98,22 @@ int ehca_create_eq(struct ehca_shca *shca,
u64 rpage;
vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
- if (!vpage) {
- ret = H_RESOURCE;
+ if (!vpage)
goto create_eq_exit2;
- }
rpage = virt_to_abs(vpage);
- ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
- eq->ipz_eq_handle,
- &eq->pf,
- 0, 0, rpage, 1);
+ h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
+ eq->ipz_eq_handle,
+ &eq->pf,
+ 0, 0, rpage, 1);
if (i == (nr_pages - 1)) {
/* last page */
vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
- if (ret != H_SUCCESS || vpage)
+ if (h_ret != H_SUCCESS || vpage)
goto create_eq_exit2;
} else {
- if (ret != H_PAGE_REGISTERED || !vpage)
+ if (h_ret != H_PAGE_REGISTERED || !vpage)
goto create_eq_exit2;
}
}
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index 2515cbde7e65..bc3b37d2070f 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -101,7 +101,6 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
props->max_ee = limit_uint(rblock->max_rd_ee_context);
props->max_rdd = limit_uint(rblock->max_rd_domain);
props->max_fmr = limit_uint(rblock->max_mr);
- props->local_ca_ack_delay = limit_uint(rblock->local_ca_ack_delay);
props->max_qp_rd_atom = limit_uint(rblock->max_rr_qp);
props->max_ee_rd_atom = limit_uint(rblock->max_rr_ee_context);
props->max_res_rd_atom = limit_uint(rblock->max_rr_hca);
@@ -115,7 +114,7 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
}
props->max_pkeys = 16;
- props->local_ca_ack_delay = limit_uint(rblock->local_ca_ack_delay);
+ props->local_ca_ack_delay = min_t(u8, rblock->local_ca_ack_delay, 255);
props->max_raw_ipv6_qp = limit_uint(rblock->max_raw_ipv6_qp);
props->max_raw_ethy_qp = limit_uint(rblock->max_raw_ethy_qp);
props->max_mcast_grp = limit_uint(rblock->max_mcast_grp);
@@ -136,7 +135,7 @@ query_device1:
return ret;
}
-static int map_mtu(struct ehca_shca *shca, u32 fw_mtu)
+static enum ib_mtu map_mtu(struct ehca_shca *shca, u32 fw_mtu)
{
switch (fw_mtu) {
case 0x1:
@@ -156,7 +155,7 @@ static int map_mtu(struct ehca_shca *shca, u32 fw_mtu)
}
}
-static int map_number_of_vls(struct ehca_shca *shca, u32 vl_cap)
+static u8 map_number_of_vls(struct ehca_shca *shca, u32 vl_cap)
{
switch (vl_cap) {
case 0x1:
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index ca5eb0cb628c..ce1ab0571be3 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -204,6 +204,8 @@ static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
read_lock(&ehca_qp_idr_lock);
qp = idr_find(&ehca_qp_idr, token);
+ if (qp)
+ atomic_inc(&qp->nr_events);
read_unlock(&ehca_qp_idr_lock);
if (!qp)
@@ -223,6 +225,8 @@ static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
if (fatal && qp->ext_type == EQPT_SRQBASE)
dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
+ if (atomic_dec_and_test(&qp->nr_events))
+ wake_up(&qp->wait_completion);
return;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 65048976198c..482103eb6eac 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -68,6 +68,8 @@ int ehca_port_act_time = 30;
int ehca_static_rate = -1;
int ehca_scaling_code = 0;
int ehca_lock_hcalls = -1;
+int ehca_max_cq = -1;
+int ehca_max_qp = -1;
module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO);
module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);
@@ -79,6 +81,8 @@ module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO);
module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);
module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO);
module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO);
+module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO);
+module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO);
MODULE_PARM_DESC(open_aqp1,
"Open AQP1 on startup (default: no)");
@@ -104,6 +108,12 @@ MODULE_PARM_DESC(scaling_code,
MODULE_PARM_DESC(lock_hcalls,
"Serialize all hCalls made by the driver "
"(default: autodetect)");
+MODULE_PARM_DESC(number_of_cqs,
+ "Max number of CQs which can be allocated "
+ "(default: autodetect)");
+MODULE_PARM_DESC(number_of_qps,
+ "Max number of QPs which can be allocated "
+ "(default: autodetect)");
DEFINE_RWLOCK(ehca_qp_idr_lock);
DEFINE_RWLOCK(ehca_cq_idr_lock);
@@ -355,6 +365,25 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
if (rblock->memory_page_size_supported & pgsize_map[i])
shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
+ /* Set maximum number of CQs and QPs to calculate EQ size */
+ if (ehca_max_qp == -1)
+ ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES);
+ else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) {
+ ehca_gen_err("Requested number of QPs is out of range (1 - %i) "
+ "specified by HW", rblock->max_qp);
+ ret = -EINVAL;
+ goto sense_attributes1;
+ }
+
+ if (ehca_max_cq == -1)
+ ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES);
+ else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) {
+ ehca_gen_err("Requested number of CQs is out of range (1 - %i) "
+ "specified by HW", rblock->max_cq);
+ ret = -EINVAL;
+ goto sense_attributes1;
+ }
+
/* query max MTU from first port -- it's the same for all ports */
port = (struct hipz_query_port *)rblock;
h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
@@ -684,7 +713,7 @@ static int __devinit ehca_probe(struct of_device *dev,
struct ehca_shca *shca;
const u64 *handle;
struct ib_pd *ibpd;
- int ret, i;
+ int ret, i, eq_size;
handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
if (!handle) {
@@ -705,6 +734,8 @@ static int __devinit ehca_probe(struct of_device *dev,
return -ENOMEM;
}
mutex_init(&shca->modify_mutex);
+ atomic_set(&shca->num_cqs, 0);
+ atomic_set(&shca->num_qps, 0);
for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
spin_lock_init(&shca->sport[i].mod_sqp_lock);
@@ -724,8 +755,9 @@ static int __devinit ehca_probe(struct of_device *dev,
goto probe1;
}
+ eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp;
/* create event queues */
- ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
+ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size);
if (ret) {
ehca_err(&shca->ib_device, "Cannot create EQ.");
goto probe1;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index 46ae4eb2c4e1..f974367cad40 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -323,7 +323,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
- mr_access_flags);
+ mr_access_flags, 0);
if (IS_ERR(e_mr->umem)) {
ib_mr = (void *)e_mr->umem;
goto reg_user_mr_exit1;
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 57bef1152cc2..3f59587338ea 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -421,8 +421,18 @@ static struct ehca_qp *internal_create_qp(
u32 swqe_size = 0, rwqe_size = 0, ib_qp_num;
unsigned long flags;
- if (init_attr->create_flags)
+ if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) {
+ ehca_err(pd->device, "Unable to create QP, max number of %i "
+ "QPs reached.", ehca_max_qp);
+ ehca_err(pd->device, "To increase the maximum number of QPs "
+ "use the number_of_qps module parameter.\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ if (init_attr->create_flags) {
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
+ }
memset(&parms, 0, sizeof(parms));
qp_type = init_attr->qp_type;
@@ -431,6 +441,7 @@ static struct ehca_qp *internal_create_qp(
init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",
init_attr->sq_sig_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
@@ -455,6 +466,7 @@ static struct ehca_qp *internal_create_qp(
if (is_llqp && has_srq) {
ehca_err(pd->device, "LLQPs can't have an SRQ");
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
@@ -466,6 +478,7 @@ static struct ehca_qp *internal_create_qp(
ehca_err(pd->device, "no more than three SGEs "
"supported for SRQ pd=%p max_sge=%x",
pd, init_attr->cap.max_recv_sge);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
}
@@ -477,6 +490,7 @@ static struct ehca_qp *internal_create_qp(
qp_type != IB_QPT_SMI &&
qp_type != IB_QPT_GSI) {
ehca_err(pd->device, "wrong QP Type=%x", qp_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
@@ -490,6 +504,7 @@ static struct ehca_qp *internal_create_qp(
"or max_rq_wr=%x for RC LLQP",
init_attr->cap.max_send_wr,
init_attr->cap.max_recv_wr);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
break;
@@ -497,6 +512,7 @@ static struct ehca_qp *internal_create_qp(
if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) {
ehca_err(pd->device, "UD LLQP not supported "
"by this adapter");
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-ENOSYS);
}
if (!(init_attr->cap.max_send_sge <= 5
@@ -508,20 +524,22 @@ static struct ehca_qp *internal_create_qp(
"or max_recv_sge=%x for UD LLQP",
init_attr->cap.max_send_sge,
init_attr->cap.max_recv_sge);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
} else if (init_attr->cap.max_send_wr > 255) {
ehca_err(pd->device,
"Invalid Number of "
"max_send_wr=%x for UD QP_TYPE=%x",
init_attr->cap.max_send_wr, qp_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
break;
default:
ehca_err(pd->device, "unsupported LL QP Type=%x",
qp_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
- break;
}
} else {
int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI
@@ -533,6 +551,7 @@ static struct ehca_qp *internal_create_qp(
"send_sge=%x recv_sge=%x max_sge=%x",
init_attr->cap.max_send_sge,
init_attr->cap.max_recv_sge, max_sge);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
}
@@ -543,9 +562,12 @@ static struct ehca_qp *internal_create_qp(
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);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-ENOMEM);
}
+ atomic_set(&my_qp->nr_events, 0);
+ init_waitqueue_head(&my_qp->wait_completion);
spin_lock_init(&my_qp->spinlock_s);
spin_lock_init(&my_qp->spinlock_r);
my_qp->qp_type = qp_type;
@@ -823,6 +845,7 @@ create_qp_exit1:
create_qp_exit0:
kmem_cache_free(qp_cache, my_qp);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(ret);
}
@@ -1913,6 +1936,9 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
idr_remove(&ehca_qp_idr, my_qp->token);
write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ /* now wait until all pending events have completed */
+ wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
+
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "
@@ -1948,6 +1974,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
if (HAS_SQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
kmem_cache_free(qp_cache, my_qp);
+ atomic_dec(&shca->num_qps);
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index acf30c06a0c0..daad09a45910 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1197,7 +1197,7 @@ void ipath_kreceive(struct ipath_portdata *pd)
}
reloop:
- for (last = 0, i = 1; !last; i++) {
+ for (last = 0, i = 1; !last; i += !last) {
hdr = dd->ipath_f_get_msgheader(dd, rhf_addr);
eflags = ipath_hdrget_err_flags(rhf_addr);
etype = ipath_hdrget_rcv_type(rhf_addr);
@@ -1428,6 +1428,40 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
}
+/*
+ * used to force update of pioavailshadow if we can't get a pio buffer.
+ * Needed primarily due to exitting freeze mode after recovering
+ * from errors. Done lazily, because it's safer (known to not
+ * be writing pio buffers).
+ */
+static void ipath_reset_availshadow(struct ipath_devdata *dd)
+{
+ int i, im;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipath_pioavail_lock, flags);
+ for (i = 0; i < dd->ipath_pioavregs; i++) {
+ u64 val, oldval;
+ /* deal with 6110 chip bug on high register #s */
+ im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
+ i ^ 1 : i;
+ val = le64_to_cpu(dd->ipath_pioavailregs_dma[im]);
+ /*
+ * busy out the buffers not in the kernel avail list,
+ * without changing the generation bits.
+ */
+ oldval = dd->ipath_pioavailshadow[i];
+ dd->ipath_pioavailshadow[i] = val |
+ ((~dd->ipath_pioavailkernel[i] <<
+ INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT) &
+ 0xaaaaaaaaaaaaaaaaULL); /* All BUSY bits in qword */
+ if (oldval != dd->ipath_pioavailshadow[i])
+ ipath_dbg("shadow[%d] was %Lx, now %lx\n",
+ i, oldval, dd->ipath_pioavailshadow[i]);
+ }
+ spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
+}
+
/**
* ipath_setrcvhdrsize - set the receive header size
* @dd: the infinipath device
@@ -1482,9 +1516,12 @@ static noinline void no_pio_bufs(struct ipath_devdata *dd)
*/
ipath_stats.sps_nopiobufs++;
if (!(++dd->ipath_consec_nopiobuf % 100000)) {
- ipath_dbg("%u pio sends with no bufavail; dmacopy: "
- "%llx %llx %llx %llx; shadow: %lx %lx %lx %lx\n",
+ ipath_force_pio_avail_update(dd); /* at start */
+ ipath_dbg("%u tries no piobufavail ts%lx; dmacopy: "
+ "%llx %llx %llx %llx\n"
+ "ipath shadow: %lx %lx %lx %lx\n",
dd->ipath_consec_nopiobuf,
+ (unsigned long)get_cycles(),
(unsigned long long) le64_to_cpu(dma[0]),
(unsigned long long) le64_to_cpu(dma[1]),
(unsigned long long) le64_to_cpu(dma[2]),
@@ -1496,14 +1533,17 @@ static noinline void no_pio_bufs(struct ipath_devdata *dd)
*/
if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) >
(sizeof(shadow[0]) * 4 * 4))
- ipath_dbg("2nd group: dmacopy: %llx %llx "
- "%llx %llx; shadow: %lx %lx %lx %lx\n",
+ ipath_dbg("2nd group: dmacopy: "
+ "%llx %llx %llx %llx\n"
+ "ipath shadow: %lx %lx %lx %lx\n",
(unsigned long long)le64_to_cpu(dma[4]),
(unsigned long long)le64_to_cpu(dma[5]),
(unsigned long long)le64_to_cpu(dma[6]),
(unsigned long long)le64_to_cpu(dma[7]),
- shadow[4], shadow[5], shadow[6],
- shadow[7]);
+ shadow[4], shadow[5], shadow[6], shadow[7]);
+
+ /* at end, so update likely happened */
+ ipath_reset_availshadow(dd);
}
}
@@ -1652,19 +1692,46 @@ void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
unsigned len, int avail)
{
unsigned long flags;
- unsigned end;
+ unsigned end, cnt = 0, next;
/* There are two bits per send buffer (busy and generation) */
start *= 2;
- len *= 2;
- end = start + len;
+ end = start + len * 2;
- /* Set or clear the generation bits. */
spin_lock_irqsave(&ipath_pioavail_lock, flags);
+ /* Set or clear the busy bit in the shadow. */
while (start < end) {
if (avail) {
- __clear_bit(start + INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT,
- dd->ipath_pioavailshadow);
+ unsigned long dma;
+ int i, im;
+ /*
+ * the BUSY bit will never be set, because we disarm
+ * the user buffers before we hand them back to the
+ * kernel. We do have to make sure the generation
+ * bit is set correctly in shadow, since it could
+ * have changed many times while allocated to user.
+ * We can't use the bitmap functions on the full
+ * dma array because it is always little-endian, so
+ * we have to flip to host-order first.
+ * BITS_PER_LONG is slightly wrong, since it's
+ * always 64 bits per register in chip...
+ * We only work on 64 bit kernels, so that's OK.
+ */
+ /* deal with 6110 chip bug on high register #s */
+ i = start / BITS_PER_LONG;
+ im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
+ i ^ 1 : i;
+ __clear_bit(INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT
+ + start, dd->ipath_pioavailshadow);
+ dma = (unsigned long) le64_to_cpu(
+ dd->ipath_pioavailregs_dma[im]);
+ if (test_bit((INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
+ + start) % BITS_PER_LONG, &dma))
+ __set_bit(INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
+ + start, dd->ipath_pioavailshadow);
+ else
+ __clear_bit(INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
+ + start, dd->ipath_pioavailshadow);
__set_bit(start, dd->ipath_pioavailkernel);
} else {
__set_bit(start + INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT,
@@ -1673,7 +1740,44 @@ void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
}
start += 2;
}
+
+ if (dd->ipath_pioupd_thresh) {
+ end = 2 * (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
+ next = find_first_bit(dd->ipath_pioavailkernel, end);
+ while (next < end) {
+ cnt++;
+ next = find_next_bit(dd->ipath_pioavailkernel, end,
+ next + 1);
+ }
+ }
spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
+
+ /*
+ * When moving buffers from kernel to user, if number assigned to
+ * the user is less than the pio update threshold, and threshold
+ * is supported (cnt was computed > 0), drop the update threshold
+ * so we update at least once per allocated number of buffers.
+ * In any case, if the kernel buffers are less than the threshold,
+ * drop the threshold. We don't bother increasing it, having once
+ * decreased it, since it would typically just cycle back and forth.
+ * If we don't decrease below buffers in use, we can wait a long
+ * time for an update, until some other context uses PIO buffers.
+ */
+ if (!avail && len < cnt)
+ cnt = len;
+ if (cnt < dd->ipath_pioupd_thresh) {
+ dd->ipath_pioupd_thresh = cnt;
+ ipath_dbg("Decreased pio update threshold to %u\n",
+ dd->ipath_pioupd_thresh);
+ spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ dd->ipath_sendctrl &= ~(INFINIPATH_S_UPDTHRESH_MASK
+ << INFINIPATH_S_UPDTHRESH_SHIFT);
+ dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
+ << INFINIPATH_S_UPDTHRESH_SHIFT;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ dd->ipath_sendctrl);
+ spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ }
}
/**
@@ -1790,12 +1894,12 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
*/
if (dd->ipath_flags & IPATH_HAS_SEND_DMA) {
int skip_cancel;
- u64 *statp = &dd->ipath_sdma_status;
+ unsigned long *statp = &dd->ipath_sdma_status;
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
skip_cancel =
- !test_bit(IPATH_SDMA_DISABLED, statp) &&
- test_and_set_bit(IPATH_SDMA_ABORTING, statp);
+ test_and_set_bit(IPATH_SDMA_ABORTING, statp)
+ && !test_bit(IPATH_SDMA_DISABLED, statp);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (skip_cancel)
goto bail;
@@ -1826,6 +1930,9 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
ipath_disarm_piobufs(dd, 0,
dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
+ if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
+ set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
+
if (restore_sendctrl) {
/* else done by caller later if needed */
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
@@ -1845,7 +1952,6 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
/* only wait so long for intr */
dd->ipath_sdma_abort_intr_timeout = jiffies + HZ;
dd->ipath_sdma_reset_wait = 200;
- __set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
@@ -2510,7 +2616,7 @@ int ipath_reset_device(int unit)
ipath_dbg("unit %u port %d is in use "
"(PID %u cmd %s), can't reset\n",
unit, i,
- dd->ipath_pd[i]->port_pid,
+ pid_nr(dd->ipath_pd[i]->port_pid),
dd->ipath_pd[i]->port_comm);
ret = -EBUSY;
goto bail;
@@ -2548,19 +2654,21 @@ bail:
static int ipath_signal_procs(struct ipath_devdata *dd, int sig)
{
int i, sub, any = 0;
- pid_t pid;
+ struct pid *pid;
if (!dd->ipath_pd)
return 0;
for (i = 1; i < dd->ipath_cfgports; i++) {
- if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt ||
- !dd->ipath_pd[i]->port_pid)
+ if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
continue;
pid = dd->ipath_pd[i]->port_pid;
+ if (!pid)
+ continue;
+
dev_info(&dd->pcidev->dev, "context %d in use "
"(PID %u), sending signal %d\n",
- i, pid, sig);
- kill_proc(pid, sig, 1);
+ i, pid_nr(pid), sig);
+ kill_pid(pid, sig, 1);
any++;
for (sub = 0; sub < INFINIPATH_MAX_SUBPORT; sub++) {
pid = dd->ipath_pd[i]->port_subpid[sub];
@@ -2568,8 +2676,8 @@ static int ipath_signal_procs(struct ipath_devdata *dd, int sig)
continue;
dev_info(&dd->pcidev->dev, "sub-context "
"%d:%d in use (PID %u), sending "
- "signal %d\n", i, sub, pid, sig);
- kill_proc(pid, sig, 1);
+ "signal %d\n", i, sub, pid_nr(pid), sig);
+ kill_pid(pid, sig, 1);
any++;
}
}
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 8b1752202e78..b472b15637f0 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -173,47 +173,25 @@ static int ipath_get_base_info(struct file *fp,
(void *) dd->ipath_statusp -
(void *) dd->ipath_pioavailregs_dma;
if (!shared) {
- kinfo->spi_piocnt = dd->ipath_pbufsport;
+ kinfo->spi_piocnt = pd->port_piocnt;
kinfo->spi_piobufbase = (u64) pd->port_piobufs;
kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
dd->ipath_ureg_align * pd->port_port;
} else if (master) {
- kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
- (dd->ipath_pbufsport % subport_cnt);
+ kinfo->spi_piocnt = (pd->port_piocnt / subport_cnt) +
+ (pd->port_piocnt % subport_cnt);
/* Master's PIO buffers are after all the slave's */
kinfo->spi_piobufbase = (u64) pd->port_piobufs +
dd->ipath_palign *
- (dd->ipath_pbufsport - kinfo->spi_piocnt);
+ (pd->port_piocnt - kinfo->spi_piocnt);
} else {
unsigned slave = subport_fp(fp) - 1;
- kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt;
+ kinfo->spi_piocnt = pd->port_piocnt / subport_cnt;
kinfo->spi_piobufbase = (u64) pd->port_piobufs +
dd->ipath_palign * kinfo->spi_piocnt * slave;
}
- /*
- * Set the PIO avail update threshold to no larger
- * than the number of buffers per process. Note that
- * we decrease it here, but won't ever increase it.
- */
- if (dd->ipath_pioupd_thresh &&
- kinfo->spi_piocnt < dd->ipath_pioupd_thresh) {
- unsigned long flags;
-
- dd->ipath_pioupd_thresh = kinfo->spi_piocnt;
- ipath_dbg("Decreased pio update threshold to %u\n",
- dd->ipath_pioupd_thresh);
- spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- dd->ipath_sendctrl &= ~(INFINIPATH_S_UPDTHRESH_MASK
- << INFINIPATH_S_UPDTHRESH_SHIFT);
- dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
- << INFINIPATH_S_UPDTHRESH_SHIFT;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- dd->ipath_sendctrl);
- spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- }
-
if (shared) {
kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
dd->ipath_ureg_align * pd->port_port;
@@ -577,7 +555,7 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
p = dd->ipath_pageshadow[porttid + tid];
dd->ipath_pageshadow[porttid + tid] = NULL;
ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n",
- pd->port_pid, tid);
+ pid_nr(pd->port_pid), tid);
dd->ipath_f_put_tid(dd, &tidbase[tid],
RCVHQ_RCV_TYPE_EXPECTED,
dd->ipath_tidinvalid);
@@ -1309,19 +1287,19 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
if (!pd->port_subport_cnt) {
/* port is not shared */
- piocnt = dd->ipath_pbufsport;
+ piocnt = pd->port_piocnt;
piobufs = pd->port_piobufs;
} else if (!subport_fp(fp)) {
/* caller is the master */
- piocnt = (dd->ipath_pbufsport / pd->port_subport_cnt) +
- (dd->ipath_pbufsport % pd->port_subport_cnt);
+ piocnt = (pd->port_piocnt / pd->port_subport_cnt) +
+ (pd->port_piocnt % pd->port_subport_cnt);
piobufs = pd->port_piobufs +
- dd->ipath_palign * (dd->ipath_pbufsport - piocnt);
+ dd->ipath_palign * (pd->port_piocnt - piocnt);
} else {
unsigned slave = subport_fp(fp) - 1;
/* caller is a slave */
- piocnt = dd->ipath_pbufsport / pd->port_subport_cnt;
+ piocnt = pd->port_piocnt / pd->port_subport_cnt;
piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave;
}
@@ -1631,11 +1609,8 @@ static int try_alloc_port(struct ipath_devdata *dd, int port,
port);
pd->port_cnt = 1;
port_fp(fp) = pd;
- pd->port_pid = current->pid;
+ pd->port_pid = get_pid(task_pid(current));
strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm));
- ipath_chg_pioavailkernel(dd,
- dd->ipath_pbufsport * (pd->port_port - 1),
- dd->ipath_pbufsport, 0);
ipath_stats.sps_ports++;
ret = 0;
} else
@@ -1818,14 +1793,15 @@ static int find_shared_port(struct file *fp,
}
port_fp(fp) = pd;
subport_fp(fp) = pd->port_cnt++;
- pd->port_subpid[subport_fp(fp)] = current->pid;
+ pd->port_subpid[subport_fp(fp)] =
+ get_pid(task_pid(current));
tidcursor_fp(fp) = 0;
pd->active_slaves |= 1 << subport_fp(fp);
ipath_cdbg(PROC,
"%s[%u] %u sharing %s[%u] unit:port %u:%u\n",
current->comm, current->pid,
subport_fp(fp),
- pd->port_comm, pd->port_pid,
+ pd->port_comm, pid_nr(pd->port_pid),
dd->ipath_unit, pd->port_port);
ret = 1;
goto done;
@@ -1938,11 +1914,25 @@ static int ipath_do_user_init(struct file *fp,
/* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
+ /* some ports may get extra buffers, calculate that here */
+ if (pd->port_port <= dd->ipath_ports_extrabuf)
+ pd->port_piocnt = dd->ipath_pbufsport + 1;
+ else
+ pd->port_piocnt = dd->ipath_pbufsport;
+
/* for right now, kernel piobufs are at end, so port 1 is at 0 */
+ if (pd->port_port <= dd->ipath_ports_extrabuf)
+ pd->port_pio_base = (dd->ipath_pbufsport + 1)
+ * (pd->port_port - 1);
+ else
+ pd->port_pio_base = dd->ipath_ports_extrabuf +
+ dd->ipath_pbufsport * (pd->port_port - 1);
pd->port_piobufs = dd->ipath_piobufbase +
- dd->ipath_pbufsport * (pd->port_port - 1) * dd->ipath_palign;
- ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
- pd->port_port, pd->port_piobufs);
+ pd->port_pio_base * dd->ipath_palign;
+ ipath_cdbg(VERBOSE, "piobuf base for port %u is 0x%x, piocnt %u,"
+ " first pio %u\n", pd->port_port, pd->port_piobufs,
+ pd->port_piocnt, pd->port_pio_base);
+ ipath_chg_pioavailkernel(dd, pd->port_pio_base, pd->port_piocnt, 0);
/*
* Now allocate the rcvhdr Q and eager TIDs; skip the TID
@@ -2077,7 +2067,8 @@ static int ipath_close(struct inode *in, struct file *fp)
* the slave(s) don't wait for receive data forever.
*/
pd->active_slaves &= ~(1 << fd->subport);
- pd->port_subpid[fd->subport] = 0;
+ put_pid(pd->port_subpid[fd->subport]);
+ pd->port_subpid[fd->subport] = NULL;
mutex_unlock(&ipath_mutex);
goto bail;
}
@@ -2085,7 +2076,7 @@ static int ipath_close(struct inode *in, struct file *fp)
if (pd->port_hdrqfull) {
ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors "
- "during run\n", pd->port_comm, pd->port_pid,
+ "during run\n", pd->port_comm, pid_nr(pd->port_pid),
pd->port_hdrqfull);
pd->port_hdrqfull = 0;
}
@@ -2107,7 +2098,6 @@ static int ipath_close(struct inode *in, struct file *fp)
}
if (dd->ipath_kregbase) {
- int i;
/* atomically clear receive enable port and intr avail. */
clear_bit(dd->ipath_r_portenable_shift + port,
&dd->ipath_rcvctrl);
@@ -2136,9 +2126,9 @@ static int ipath_close(struct inode *in, struct file *fp)
ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
pd->port_port, dd->ipath_dummy_hdrq_phys);
- i = dd->ipath_pbufsport * (port - 1);
- ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
- ipath_chg_pioavailkernel(dd, i, dd->ipath_pbufsport, 1);
+ ipath_disarm_piobufs(dd, pd->port_pio_base, pd->port_piocnt);
+ ipath_chg_pioavailkernel(dd, pd->port_pio_base,
+ pd->port_piocnt, 1);
dd->ipath_f_clear_tids(dd, pd->port_port);
@@ -2146,11 +2136,12 @@ static int ipath_close(struct inode *in, struct file *fp)
unlock_expected_tids(pd);
ipath_stats.sps_ports--;
ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
- pd->port_comm, pd->port_pid,
+ pd->port_comm, pid_nr(pd->port_pid),
dd->ipath_unit, port);
}
- pd->port_pid = 0;
+ put_pid(pd->port_pid);
+ pd->port_pid = NULL;
dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
mutex_unlock(&ipath_mutex);
ipath_free_pddata(dd, pd); /* after releasing the mutex */
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c
index e3ec0d1bdf50..8eee7830f042 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba7220.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c
@@ -595,7 +595,7 @@ static void ipath_7220_txe_recover(struct ipath_devdata *dd)
dev_info(&dd->pcidev->dev,
"Recovering from TXE PIO parity error\n");
- ipath_disarm_senderrbufs(dd, 1);
+ ipath_disarm_senderrbufs(dd);
}
@@ -675,10 +675,8 @@ static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
/*
- * Parity errors in send memory are recoverable,
- * just cancel the send (if indicated in * sendbuffererror),
- * count the occurrence, unfreeze (if no other handled
- * hardware error bits are set), and continue.
+ * Parity errors in send memory are recoverable by h/w
+ * just do housekeeping, exit freeze mode and continue.
*/
if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
@@ -687,13 +685,6 @@ static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
<< INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
- if (!hwerrs) {
- /* else leave in freeze mode */
- ipath_write_kreg(dd,
- dd->ipath_kregs->kr_control,
- dd->ipath_control);
- goto bail;
- }
}
if (hwerrs) {
/*
@@ -723,8 +714,8 @@ static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
dd->ipath_flags &= ~IPATH_INITTED;
} else {
- ipath_dbg("Clearing freezemode on ignored hardware "
- "error\n");
+ ipath_dbg("Clearing freezemode on ignored or "
+ "recovered hardware error\n");
ipath_clear_freeze(dd);
}
}
@@ -870,8 +861,9 @@ static int ipath_7220_boardname(struct ipath_devdata *dd, char *name,
"revision %u.%u!\n",
dd->ipath_majrev, dd->ipath_minrev);
ret = 1;
- } else if (dd->ipath_minrev == 1) {
- /* Rev1 chips are prototype. Complain, but allow use */
+ } else if (dd->ipath_minrev == 1 &&
+ !(dd->ipath_flags & IPATH_INITTED)) {
+ /* Rev1 chips are prototype. Complain at init, but allow use */
ipath_dev_err(dd, "Unsupported hardware "
"revision %u.%u, Contact support@qlogic.com\n",
dd->ipath_majrev, dd->ipath_minrev);
@@ -1966,7 +1958,7 @@ static void ipath_7220_config_ports(struct ipath_devdata *dd, ushort cfgports)
dd->ipath_rcvctrl);
dd->ipath_p0_rcvegrcnt = 2048; /* always */
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
- dd->ipath_pioreserved = 1; /* reserve a buffer */
+ dd->ipath_pioreserved = 3; /* kpiobufs used for PIO */
}
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 27dd89476660..3e5baa43fc82 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -41,7 +41,7 @@
/*
* min buffers we want to have per port, after driver
*/
-#define IPATH_MIN_USER_PORT_BUFCNT 8
+#define IPATH_MIN_USER_PORT_BUFCNT 7
/*
* Number of ports we are configured to use (to allow for more pio
@@ -54,13 +54,9 @@ MODULE_PARM_DESC(cfgports, "Set max number of ports to use");
/*
* Number of buffers reserved for driver (verbs and layered drivers.)
- * Reserved at end of buffer list. Initialized based on
- * number of PIO buffers if not set via module interface.
+ * Initialized based on number of PIO buffers if not set via module interface.
* The problem with this is that it's global, but we'll use different
- * numbers for different chip types. So the default value is not
- * very useful. I've redefined it for the 1.3 release so that it's
- * zero unless set by the user to something else, in which case we
- * try to respect it.
+ * numbers for different chip types.
*/
static ushort ipath_kpiobufs;
@@ -546,9 +542,12 @@ static void enable_chip(struct ipath_devdata *dd, int reinit)
pioavail = dd->ipath_pioavailregs_dma[i ^ 1];
else
pioavail = dd->ipath_pioavailregs_dma[i];
- dd->ipath_pioavailshadow[i] = le64_to_cpu(pioavail) |
- (~dd->ipath_pioavailkernel[i] <<
- INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT);
+ /*
+ * don't need to worry about ipath_pioavailkernel here
+ * because we will call ipath_chg_pioavailkernel() later
+ * in initialization, to busy out buffers as needed
+ */
+ dd->ipath_pioavailshadow[i] = le64_to_cpu(pioavail);
}
/* can get counters, stats, etc. */
dd->ipath_flags |= IPATH_PRESENT;
@@ -708,12 +707,11 @@ static void verify_interrupt(unsigned long opaque)
int ipath_init_chip(struct ipath_devdata *dd, int reinit)
{
int ret = 0;
- u32 val32, kpiobufs;
+ u32 kpiobufs, defkbufs;
u32 piobufs, uports;
u64 val;
struct ipath_portdata *pd;
gfp_t gfp_flags = GFP_USER | __GFP_COMP;
- unsigned long flags;
ret = init_housekeeping(dd, reinit);
if (ret)
@@ -753,56 +751,46 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
dd->ipath_pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2)
/ (sizeof(u64) * BITS_PER_BYTE / 2);
uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0;
- if (ipath_kpiobufs == 0) {
- /* not set by user (this is default) */
- if (piobufs > 144)
- kpiobufs = 32;
- else
- kpiobufs = 16;
- }
+ if (piobufs > 144)
+ defkbufs = 32 + dd->ipath_pioreserved;
else
- kpiobufs = ipath_kpiobufs;
+ defkbufs = 16 + dd->ipath_pioreserved;
- if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
+ if (ipath_kpiobufs && (ipath_kpiobufs +
+ (uports * IPATH_MIN_USER_PORT_BUFCNT)) > piobufs) {
int i = (int) piobufs -
(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
if (i < 1)
i = 1;
dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs of "
"%d for kernel leaves too few for %d user ports "
- "(%d each); using %u\n", kpiobufs,
+ "(%d each); using %u\n", ipath_kpiobufs,
piobufs, uports, IPATH_MIN_USER_PORT_BUFCNT, i);
/*
* shouldn't change ipath_kpiobufs, because could be
* different for different devices...
*/
kpiobufs = i;
- }
+ } else if (ipath_kpiobufs)
+ kpiobufs = ipath_kpiobufs;
+ else
+ kpiobufs = defkbufs;
dd->ipath_lastport_piobuf = piobufs - kpiobufs;
dd->ipath_pbufsport =
uports ? dd->ipath_lastport_piobuf / uports : 0;
- val32 = dd->ipath_lastport_piobuf - (dd->ipath_pbufsport * uports);
- if (val32 > 0) {
- ipath_dbg("allocating %u pbufs/port leaves %u unused, "
- "add to kernel\n", dd->ipath_pbufsport, val32);
- dd->ipath_lastport_piobuf -= val32;
- kpiobufs += val32;
- ipath_dbg("%u pbufs/port leaves %u unused, add to kernel\n",
- dd->ipath_pbufsport, val32);
- }
+ /* if not an even divisor, some user ports get extra buffers */
+ dd->ipath_ports_extrabuf = dd->ipath_lastport_piobuf -
+ (dd->ipath_pbufsport * uports);
+ if (dd->ipath_ports_extrabuf)
+ ipath_dbg("%u pbufs/port leaves some unused, add 1 buffer to "
+ "ports <= %u\n", dd->ipath_pbufsport,
+ dd->ipath_ports_extrabuf);
dd->ipath_lastpioindex = 0;
dd->ipath_lastpioindexl = dd->ipath_piobcnt2k;
- ipath_chg_pioavailkernel(dd, 0, piobufs, 1);
+ /* ipath_pioavailshadow initialized earlier */
ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u "
"each for %u user ports\n", kpiobufs,
piobufs, dd->ipath_pbufsport, uports);
- if (dd->ipath_pioupd_thresh) {
- if (dd->ipath_pbufsport < dd->ipath_pioupd_thresh)
- dd->ipath_pioupd_thresh = dd->ipath_pbufsport;
- if (kpiobufs < dd->ipath_pioupd_thresh)
- dd->ipath_pioupd_thresh = kpiobufs;
- }
-
ret = dd->ipath_f_early_init(dd);
if (ret) {
ipath_dev_err(dd, "Early initialization failure\n");
@@ -810,13 +798,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
}
/*
- * Cancel any possible active sends from early driver load.
- * Follows early_init because some chips have to initialize
- * PIO buffers in early_init to avoid false parity errors.
- */
- ipath_cancel_sends(dd, 0);
-
- /*
* Early_init sets rcvhdrentsize and rcvhdrsize, so this must be
* done after early_init.
*/
@@ -836,6 +817,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendpioavailaddr,
dd->ipath_pioavailregs_phys);
+
/*
* this is to detect s/w errors, which the h/w works around by
* ignoring the low 6 bits of address, if it wasn't aligned.
@@ -862,12 +844,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
- spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
- ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
/*
* before error clears, since we expect serdes pll errors during
* this, the first time after reset
@@ -940,6 +916,19 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
else
enable_chip(dd, reinit);
+ /* after enable_chip, so pioavailshadow setup */
+ ipath_chg_pioavailkernel(dd, 0, piobufs, 1);
+
+ /*
+ * Cancel any possible active sends from early driver load.
+ * Follows early_init because some chips have to initialize
+ * PIO buffers in early_init to avoid false parity errors.
+ * After enable and ipath_chg_pioavailkernel so we can safely
+ * enable pioavail updates and PIOENABLE; packets are now
+ * ready to go out.
+ */
+ ipath_cancel_sends(dd, 1);
+
if (!reinit) {
/*
* Used when we close a port, for DMA already in flight
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 1b58f4737c71..26900b3b7a4e 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -38,42 +38,12 @@
#include "ipath_verbs.h"
#include "ipath_common.h"
-/*
- * clear (write) a pio buffer, to clear a parity error. This routine
- * should only be called when in freeze mode, and the buffer should be
- * canceled afterwards.
- */
-static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
-{
- u32 __iomem *pbuf;
- u32 dwcnt; /* dword count to write */
- if (pnum < dd->ipath_piobcnt2k) {
- pbuf = (u32 __iomem *) (dd->ipath_pio2kbase + pnum *
- dd->ipath_palign);
- dwcnt = dd->ipath_piosize2k >> 2;
- }
- else {
- pbuf = (u32 __iomem *) (dd->ipath_pio4kbase +
- (pnum - dd->ipath_piobcnt2k) * dd->ipath_4kalign);
- dwcnt = dd->ipath_piosize4k >> 2;
- }
- dev_info(&dd->pcidev->dev,
- "Rewrite PIO buffer %u, to recover from parity error\n",
- pnum);
-
- /* no flush required, since already in freeze */
- writel(dwcnt + 1, pbuf);
- while (--dwcnt)
- writel(0, pbuf++);
-}
/*
* Called when we might have an error that is specific to a particular
* PIO buffer, and may need to cancel that buffer, so it can be re-used.
- * If rewrite is true, and bits are set in the sendbufferror registers,
- * we'll write to the buffer, for error recovery on parity errors.
*/
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
{
u32 piobcnt;
unsigned long sbuf[4];
@@ -109,11 +79,8 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
}
for (i = 0; i < piobcnt; i++)
- if (test_bit(i, sbuf)) {
- if (rewrite)
- ipath_clrpiobuf(dd, i);
+ if (test_bit(i, sbuf))
ipath_disarm_piobufs(dd, i, 1);
- }
/* ignore armlaunch errs for a bit */
dd->ipath_lastcancel = jiffies+3;
}
@@ -164,7 +131,7 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
{
u64 ignore_this_time = 0;
- ipath_disarm_senderrbufs(dd, 0);
+ ipath_disarm_senderrbufs(dd);
if ((errs & E_SUM_LINK_PKTERRS) &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
/*
@@ -909,8 +876,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* processes (causing armlaunch), send errors due to going into freeze mode,
* etc., and try to avoid causing extra interrupts while doing so.
* Forcibly update the in-memory pioavail register copies after cleanup
- * because the chip won't do it for anything changing while in freeze mode
- * (we don't want to wait for the next pio buffer state change).
+ * because the chip won't do it while in freeze mode (the register values
+ * themselves are kept correct).
* Make sure that we don't lose any important interrupts by using the chip
* feature that says that writing 0 to a bit in *clear that is set in
* *status will cause an interrupt to be generated again (if allowed by
@@ -918,44 +885,23 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
*/
void ipath_clear_freeze(struct ipath_devdata *dd)
{
- int i, im;
- u64 val;
-
/* disable error interrupts, to avoid confusion */
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
/* also disable interrupts; errormask is sometimes overwriten */
ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
- /*
- * clear all sends, because they have may been
- * completed by usercode while in freeze mode, and
- * therefore would not be sent, and eventually
- * might cause the process to run out of bufs
- */
- ipath_cancel_sends(dd, 0);
+ ipath_cancel_sends(dd, 1);
+
+ /* clear the freeze, and be sure chip saw it */
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- /* ensure pio avail updates continue */
+ /* force in-memory update now we are out of freeze */
ipath_force_pio_avail_update(dd);
/*
- * We just enabled pioavailupdate, so dma copy is almost certainly
- * not yet right, so read the registers directly. Similar to init
- */
- for (i = 0; i < dd->ipath_pioavregs; i++) {
- /* deal with 6110 chip bug */
- im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
- i ^ 1 : i;
- val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
- dd->ipath_pioavailregs_dma[i] = cpu_to_le64(val);
- dd->ipath_pioavailshadow[i] = val |
- (~dd->ipath_pioavailkernel[i] <<
- INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT);
- }
-
- /*
* force new interrupt if any hwerr, error or interrupt bits are
* still set, and clear "safe" send packet errors related to freeze
* and cancelling sends. Re-enable error interrupts before possible
@@ -1312,10 +1258,8 @@ irqreturn_t ipath_intr(int irq, void *data)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA))
- handle_layer_pioavail(dd);
- else
- ipath_dbg("unexpected BUFAVAIL intr\n");
+ /* always process; sdma verbs uses PIO for acks and VL15 */
+ handle_layer_pioavail(dd);
}
ret = IRQ_HANDLED;
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 202337ae90dc..59a8b254b97f 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -117,6 +117,10 @@ struct ipath_portdata {
u16 port_subport_cnt;
/* non-zero if port is being shared. */
u16 port_subport_id;
+ /* number of pio bufs for this port (all procs, if shared) */
+ u32 port_piocnt;
+ /* first pio buffer for this port */
+ u32 port_pio_base;
/* chip offset of PIO buffers for this port */
u32 port_piobufs;
/* how many alloc_pages() chunks in port_rcvegrbuf_pages */
@@ -155,8 +159,8 @@ struct ipath_portdata {
/* saved total number of polled urgent packets for poll edge trigger */
u32 port_urgent_poll;
/* pid of process using this port */
- pid_t port_pid;
- pid_t port_subpid[INFINIPATH_MAX_SUBPORT];
+ struct pid *port_pid;
+ struct pid *port_subpid[INFINIPATH_MAX_SUBPORT];
/* same size as task_struct .comm[] */
char port_comm[16];
/* pkeys set by this use of this port */
@@ -384,6 +388,8 @@ struct ipath_devdata {
u32 ipath_lastrpkts;
/* pio bufs allocated per port */
u32 ipath_pbufsport;
+ /* if remainder on bufs/port, ports < extrabuf get 1 extra */
+ u32 ipath_ports_extrabuf;
u32 ipath_pioupd_thresh; /* update threshold, some chips */
/*
* number of ports configured as max; zero is set to number chip
@@ -477,7 +483,7 @@ struct ipath_devdata {
/* SendDMA related entries */
spinlock_t ipath_sdma_lock;
- u64 ipath_sdma_status;
+ unsigned long ipath_sdma_status;
unsigned long ipath_sdma_abort_jiffies;
unsigned long ipath_sdma_abort_intr_timeout;
unsigned long ipath_sdma_buf_jiffies;
@@ -816,8 +822,8 @@ struct ipath_devdata {
#define IPATH_SDMA_DISARMED 1
#define IPATH_SDMA_DISABLED 2
#define IPATH_SDMA_LAYERBUF 3
-#define IPATH_SDMA_RUNNING 62
-#define IPATH_SDMA_SHUTDOWN 63
+#define IPATH_SDMA_RUNNING 30
+#define IPATH_SDMA_SHUTDOWN 31
/* bit combinations that correspond to abort states */
#define IPATH_SDMA_ABORT_NONE 0
@@ -1011,7 +1017,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *);
int ipath_update_eeprom_log(struct ipath_devdata *dd);
void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
+void ipath_disarm_senderrbufs(struct ipath_devdata *);
void ipath_force_pio_avail_update(struct ipath_devdata *);
void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index db4ba92f79fc..9d343b7c2f3b 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -195,7 +195,8 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
goto bail;
}
- umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags);
+ umem = ib_umem_get(pd->uobject->context, start, length,
+ mr_access_flags, 0);
if (IS_ERR(umem))
return (void *) umem;
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index dd5b6e9d57c2..4715911101e4 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -242,7 +242,6 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp)
{
struct ipath_qp *q, **qpp;
unsigned long flags;
- int fnd = 0;
spin_lock_irqsave(&qpt->lock, flags);
@@ -253,51 +252,40 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp)
*qpp = qp->next;
qp->next = NULL;
atomic_dec(&qp->refcount);
- fnd = 1;
break;
}
}
spin_unlock_irqrestore(&qpt->lock, flags);
-
- if (!fnd)
- return;
-
- free_qpn(qpt, qp->ibqp.qp_num);
-
- wait_event(qp->wait, !atomic_read(&qp->refcount));
}
/**
- * ipath_free_all_qps - remove all QPs from the table
+ * ipath_free_all_qps - check for QPs still in use
* @qpt: the QP table to empty
+ *
+ * There should not be any QPs still in use.
+ * Free memory for table.
*/
-void ipath_free_all_qps(struct ipath_qp_table *qpt)
+unsigned ipath_free_all_qps(struct ipath_qp_table *qpt)
{
unsigned long flags;
- struct ipath_qp *qp, *nqp;
- u32 n;
+ struct ipath_qp *qp;
+ u32 n, qp_inuse = 0;
+ spin_lock_irqsave(&qpt->lock, flags);
for (n = 0; n < qpt->max; n++) {
- spin_lock_irqsave(&qpt->lock, flags);
qp = qpt->table[n];
qpt->table[n] = NULL;
- spin_unlock_irqrestore(&qpt->lock, flags);
-
- while (qp) {
- nqp = qp->next;
- free_qpn(qpt, qp->ibqp.qp_num);
- if (!atomic_dec_and_test(&qp->refcount) ||
- !ipath_destroy_qp(&qp->ibqp))
- ipath_dbg("QP memory leak!\n");
- qp = nqp;
- }
+
+ for (; qp; qp = qp->next)
+ qp_inuse++;
}
+ spin_unlock_irqrestore(&qpt->lock, flags);
- for (n = 0; n < ARRAY_SIZE(qpt->map); n++) {
+ for (n = 0; n < ARRAY_SIZE(qpt->map); n++)
if (qpt->map[n].page)
- free_page((unsigned long)qpt->map[n].page);
- }
+ free_page((unsigned long) qpt->map[n].page);
+ return qp_inuse;
}
/**
@@ -336,11 +324,12 @@ static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type)
qp->remote_qpn = 0;
qp->qkey = 0;
qp->qp_access_flags = 0;
- qp->s_busy = 0;
+ atomic_set(&qp->s_dma_busy, 0);
qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
qp->s_hdrwords = 0;
qp->s_wqe = NULL;
qp->s_pkt_delay = 0;
+ qp->s_draining = 0;
qp->s_psn = 0;
qp->r_psn = 0;
qp->r_msn = 0;
@@ -353,7 +342,8 @@ static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type)
}
qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
qp->r_nak_state = 0;
- qp->r_wrid_valid = 0;
+ qp->r_aflags = 0;
+ qp->r_flags = 0;
qp->s_rnr_timeout = 0;
qp->s_head = 0;
qp->s_tail = 0;
@@ -361,7 +351,6 @@ static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type)
qp->s_last = 0;
qp->s_ssn = 1;
qp->s_lsn = 0;
- qp->s_wait_credit = 0;
memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue));
qp->r_head_ack_queue = 0;
qp->s_tail_ack_queue = 0;
@@ -370,17 +359,17 @@ static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type)
qp->r_rq.wq->head = 0;
qp->r_rq.wq->tail = 0;
}
- qp->r_reuse_sge = 0;
}
/**
- * ipath_error_qp - put a QP into an error state
- * @qp: the QP to put into an error state
+ * ipath_error_qp - put a QP into the error state
+ * @qp: the QP to put into the error state
* @err: the receive completion error to signal if a RWQE is active
*
* Flushes both send and receive work queues.
* Returns true if last WQE event should be generated.
* The QP s_lock should be held and interrupts disabled.
+ * If we are already in error state, just return.
*/
int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
@@ -389,8 +378,10 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
struct ib_wc wc;
int ret = 0;
- ipath_dbg("QP%d/%d in error state (%d)\n",
- qp->ibqp.qp_num, qp->remote_qpn, err);
+ if (qp->state == IB_QPS_ERR)
+ goto bail;
+
+ qp->state = IB_QPS_ERR;
spin_lock(&dev->pending_lock);
if (!list_empty(&qp->timerwait))
@@ -399,39 +390,21 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
list_del_init(&qp->piowait);
spin_unlock(&dev->pending_lock);
- wc.vendor_err = 0;
- wc.byte_len = 0;
- wc.imm_data = 0;
+ /* Schedule the sending tasklet to drain the send work queue. */
+ if (qp->s_last != qp->s_head)
+ ipath_schedule_send(qp);
+
+ memset(&wc, 0, sizeof(wc));
wc.qp = &qp->ibqp;
- wc.src_qp = 0;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
- wc.slid = 0;
- wc.sl = 0;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- if (qp->r_wrid_valid) {
- qp->r_wrid_valid = 0;
+ wc.opcode = IB_WC_RECV;
+
+ if (test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags)) {
wc.wr_id = qp->r_wr_id;
- wc.opcode = IB_WC_RECV;
wc.status = err;
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
}
wc.status = IB_WC_WR_FLUSH_ERR;
- while (qp->s_last != qp->s_head) {
- struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
-
- wc.wr_id = wqe->wr.wr_id;
- wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- if (++qp->s_last >= qp->s_size)
- qp->s_last = 0;
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
- }
- qp->s_cur = qp->s_tail = qp->s_head;
- qp->s_hdrwords = 0;
- qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
-
if (qp->r_rq.wq) {
struct ipath_rwq *wq;
u32 head;
@@ -447,7 +420,6 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
tail = wq->tail;
if (tail >= qp->r_rq.size)
tail = 0;
- wc.opcode = IB_WC_RECV;
while (tail != head) {
wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id;
if (++tail >= qp->r_rq.size)
@@ -460,6 +432,7 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
} else if (qp->ibqp.event_handler)
ret = 1;
+bail:
return ret;
}
@@ -478,11 +451,10 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct ipath_ibdev *dev = to_idev(ibqp->device);
struct ipath_qp *qp = to_iqp(ibqp);
enum ib_qp_state cur_state, new_state;
- unsigned long flags;
int lastwqe = 0;
int ret;
- spin_lock_irqsave(&qp->s_lock, flags);
+ spin_lock_irq(&qp->s_lock);
cur_state = attr_mask & IB_QP_CUR_STATE ?
attr->cur_qp_state : qp->state;
@@ -535,16 +507,42 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
switch (new_state) {
case IB_QPS_RESET:
+ if (qp->state != IB_QPS_RESET) {
+ qp->state = IB_QPS_RESET;
+ spin_lock(&dev->pending_lock);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
+ if (!list_empty(&qp->piowait))
+ list_del_init(&qp->piowait);
+ spin_unlock(&dev->pending_lock);
+ qp->s_flags &= ~IPATH_S_ANY_WAIT;
+ spin_unlock_irq(&qp->s_lock);
+ /* Stop the sending tasklet */
+ tasklet_kill(&qp->s_task);
+ wait_event(qp->wait_dma, !atomic_read(&qp->s_dma_busy));
+ spin_lock_irq(&qp->s_lock);
+ }
ipath_reset_qp(qp, ibqp->qp_type);
break;
+ case IB_QPS_SQD:
+ qp->s_draining = qp->s_last != qp->s_cur;
+ qp->state = new_state;
+ break;
+
+ case IB_QPS_SQE:
+ if (qp->ibqp.qp_type == IB_QPT_RC)
+ goto inval;
+ qp->state = new_state;
+ break;
+
case IB_QPS_ERR:
lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
break;
default:
+ qp->state = new_state;
break;
-
}
if (attr_mask & IB_QP_PKEY_INDEX)
@@ -597,8 +595,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
qp->s_max_rd_atomic = attr->max_rd_atomic;
- qp->state = new_state;
- spin_unlock_irqrestore(&qp->s_lock, flags);
+ spin_unlock_irq(&qp->s_lock);
if (lastwqe) {
struct ib_event ev;
@@ -612,7 +609,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
goto bail;
inval:
- spin_unlock_irqrestore(&qp->s_lock, flags);
+ spin_unlock_irq(&qp->s_lock);
ret = -EINVAL;
bail:
@@ -643,7 +640,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
attr->pkey_index = qp->s_pkey_index;
attr->alt_pkey_index = 0;
attr->en_sqd_async_notify = 0;
- attr->sq_draining = 0;
+ attr->sq_draining = qp->s_draining;
attr->max_rd_atomic = qp->s_max_rd_atomic;
attr->max_dest_rd_atomic = qp->r_max_rd_atomic;
attr->min_rnr_timer = qp->r_min_rnr_timer;
@@ -833,6 +830,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
spin_lock_init(&qp->r_rq.lock);
atomic_set(&qp->refcount, 0);
init_waitqueue_head(&qp->wait);
+ init_waitqueue_head(&qp->wait_dma);
tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp);
INIT_LIST_HEAD(&qp->piowait);
INIT_LIST_HEAD(&qp->timerwait);
@@ -926,6 +924,7 @@ bail_ip:
else
vfree(qp->r_rq.wq);
ipath_free_qp(&dev->qp_table, qp);
+ free_qpn(&dev->qp_table, qp->ibqp.qp_num);
bail_qp:
kfree(qp);
bail_swq:
@@ -947,41 +946,44 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
{
struct ipath_qp *qp = to_iqp(ibqp);
struct ipath_ibdev *dev = to_idev(ibqp->device);
- unsigned long flags;
- spin_lock_irqsave(&qp->s_lock, flags);
- qp->state = IB_QPS_ERR;
- spin_unlock_irqrestore(&qp->s_lock, flags);
- spin_lock(&dev->n_qps_lock);
- dev->n_qps_allocated--;
- spin_unlock(&dev->n_qps_lock);
+ /* Make sure HW and driver activity is stopped. */
+ spin_lock_irq(&qp->s_lock);
+ if (qp->state != IB_QPS_RESET) {
+ qp->state = IB_QPS_RESET;
+ spin_lock(&dev->pending_lock);
+ if (!list_empty(&qp->timerwait))
+ list_del_init(&qp->timerwait);
+ if (!list_empty(&qp->piowait))
+ list_del_init(&qp->piowait);
+ spin_unlock(&dev->pending_lock);
+ qp->s_flags &= ~IPATH_S_ANY_WAIT;
+ spin_unlock_irq(&qp->s_lock);
+ /* Stop the sending tasklet */
+ tasklet_kill(&qp->s_task);
+ wait_event(qp->wait_dma, !atomic_read(&qp->s_dma_busy));
+ } else
+ spin_unlock_irq(&qp->s_lock);
- /* Stop the sending tasklet. */
- tasklet_kill(&qp->s_task);
+ ipath_free_qp(&dev->qp_table, qp);
if (qp->s_tx) {
atomic_dec(&qp->refcount);
if (qp->s_tx->txreq.flags & IPATH_SDMA_TXREQ_F_FREEBUF)
kfree(qp->s_tx->txreq.map_addr);
+ spin_lock_irq(&dev->pending_lock);
+ list_add(&qp->s_tx->txreq.list, &dev->txreq_free);
+ spin_unlock_irq(&dev->pending_lock);
+ qp->s_tx = NULL;
}
- /* Make sure the QP isn't on the timeout list. */
- spin_lock_irqsave(&dev->pending_lock, flags);
- if (!list_empty(&qp->timerwait))
- list_del_init(&qp->timerwait);
- if (!list_empty(&qp->piowait))
- list_del_init(&qp->piowait);
- if (qp->s_tx)
- list_add(&qp->s_tx->txreq.list, &dev->txreq_free);
- spin_unlock_irqrestore(&dev->pending_lock, flags);
+ wait_event(qp->wait, !atomic_read(&qp->refcount));
- /*
- * Make sure that the QP is not in the QPN table so receive
- * interrupts will discard packets for this QP. XXX Also remove QP
- * from multicast table.
- */
- if (atomic_read(&qp->refcount) != 0)
- ipath_free_qp(&dev->qp_table, qp);
+ /* all user's cleaned up, mark it available */
+ free_qpn(&dev->qp_table, qp->ibqp.qp_num);
+ spin_lock(&dev->n_qps_lock);
+ dev->n_qps_allocated--;
+ spin_unlock(&dev->n_qps_lock);
if (qp->ip)
kref_put(&qp->ip->ref, ipath_release_mmap_info);
@@ -1026,48 +1028,6 @@ bail:
}
/**
- * ipath_sqerror_qp - put a QP's send queue into an error state
- * @qp: QP who's send queue will be put into an error state
- * @wc: the WC responsible for putting the QP in this state
- *
- * Flushes the send work queue.
- * The QP s_lock should be held and interrupts disabled.
- */
-
-void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
-{
- struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
- struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
-
- ipath_dbg("Send queue error on QP%d/%d: err: %d\n",
- qp->ibqp.qp_num, qp->remote_qpn, wc->status);
-
- spin_lock(&dev->pending_lock);
- if (!list_empty(&qp->timerwait))
- list_del_init(&qp->timerwait);
- if (!list_empty(&qp->piowait))
- list_del_init(&qp->piowait);
- spin_unlock(&dev->pending_lock);
-
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1);
- if (++qp->s_last >= qp->s_size)
- qp->s_last = 0;
-
- wc->status = IB_WC_WR_FLUSH_ERR;
-
- while (qp->s_last != qp->s_head) {
- wqe = get_swqe_ptr(qp, qp->s_last);
- wc->wr_id = wqe->wr.wr_id;
- wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1);
- if (++qp->s_last >= qp->s_size)
- qp->s_last = 0;
- }
- qp->s_cur = qp->s_tail = qp->s_head;
- qp->state = IB_QPS_SQE;
-}
-
-/**
* ipath_get_credit - flush the send work queue of a QP
* @qp: the qp who's send work queue to flush
* @aeth: the Acknowledge Extended Transport Header
@@ -1093,9 +1053,10 @@ void ipath_get_credit(struct ipath_qp *qp, u32 aeth)
}
/* Restart sending if it was blocked due to lack of credits. */
- if (qp->s_cur != qp->s_head &&
+ if ((qp->s_flags & IPATH_S_WAIT_SSN_CREDIT) &&
+ qp->s_cur != qp->s_head &&
(qp->s_lsn == (u32) -1 ||
ipath_cmp24(get_swqe_ptr(qp, qp->s_cur)->ssn,
qp->s_lsn + 1) <= 0))
- tasklet_hi_schedule(&qp->s_task);
+ ipath_schedule_send(qp);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index c405dfba5531..108df667d2ee 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -92,6 +92,10 @@ static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
u32 bth0;
u32 bth2;
+ /* Don't send an ACK if we aren't supposed to. */
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
+ goto bail;
+
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
@@ -238,14 +242,25 @@ int ipath_make_rc_req(struct ipath_qp *qp)
ipath_make_rc_ack(dev, qp, ohdr, pmtu))
goto done;
- if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
- qp->s_rnr_timeout || qp->s_wait_credit)
- goto bail;
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND))
+ goto bail;
+ /* We are in the error state, flush the work request. */
+ if (qp->s_last == qp->s_head)
+ goto bail;
+ /* If DMAs are in progress, we can't flush immediately. */
+ if (atomic_read(&qp->s_dma_busy)) {
+ qp->s_flags |= IPATH_S_WAIT_DMA;
+ goto bail;
+ }
+ wqe = get_swqe_ptr(qp, qp->s_last);
+ ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+ goto done;
+ }
- /* Limit the number of packets sent without an ACK. */
- if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
- qp->s_wait_credit = 1;
- dev->n_rc_stalls++;
+ /* Leave BUSY set until RNR timeout. */
+ if (qp->s_rnr_timeout) {
+ qp->s_flags |= IPATH_S_WAITING;
goto bail;
}
@@ -257,6 +272,9 @@ int ipath_make_rc_req(struct ipath_qp *qp)
wqe = get_swqe_ptr(qp, qp->s_cur);
switch (qp->s_state) {
default:
+ if (!(ib_ipath_state_ops[qp->state] &
+ IPATH_PROCESS_NEXT_SEND_OK))
+ goto bail;
/*
* Resend an old request or start a new one.
*
@@ -294,8 +312,10 @@ int ipath_make_rc_req(struct ipath_qp *qp)
case IB_WR_SEND_WITH_IMM:
/* If no credit, return. */
if (qp->s_lsn != (u32) -1 &&
- ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0)
+ ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) {
+ qp->s_flags |= IPATH_S_WAIT_SSN_CREDIT;
goto bail;
+ }
wqe->lpsn = wqe->psn;
if (len > pmtu) {
wqe->lpsn += (len - 1) / pmtu;
@@ -325,8 +345,10 @@ int ipath_make_rc_req(struct ipath_qp *qp)
case IB_WR_RDMA_WRITE_WITH_IMM:
/* If no credit, return. */
if (qp->s_lsn != (u32) -1 &&
- ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0)
+ ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) {
+ qp->s_flags |= IPATH_S_WAIT_SSN_CREDIT;
goto bail;
+ }
ohdr->u.rc.reth.vaddr =
cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
ohdr->u.rc.reth.rkey =
@@ -570,7 +592,11 @@ int ipath_make_rc_req(struct ipath_qp *qp)
ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
done:
ret = 1;
+ goto unlock;
+
bail:
+ qp->s_flags &= ~IPATH_S_BUSY;
+unlock:
spin_unlock_irqrestore(&qp->s_lock, flags);
return ret;
}
@@ -606,7 +632,11 @@ static void send_rc_ack(struct ipath_qp *qp)
spin_unlock_irqrestore(&qp->s_lock, flags);
+ /* Don't try to send ACKs if the link isn't ACTIVE */
dd = dev->dd;
+ if (!(dd->ipath_flags & IPATH_LINKACTIVE))
+ goto done;
+
piobuf = ipath_getpiobuf(dd, 0, NULL);
if (!piobuf) {
/*
@@ -668,15 +698,16 @@ static void send_rc_ack(struct ipath_qp *qp)
goto done;
queue_ack:
- dev->n_rc_qacks++;
- qp->s_flags |= IPATH_S_ACK_PENDING;
- qp->s_nak_state = qp->r_nak_state;
- qp->s_ack_psn = qp->r_ack_psn;
+ if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK) {
+ dev->n_rc_qacks++;
+ qp->s_flags |= IPATH_S_ACK_PENDING;
+ qp->s_nak_state = qp->r_nak_state;
+ qp->s_ack_psn = qp->r_ack_psn;
+
+ /* Schedule the send tasklet. */
+ ipath_schedule_send(qp);
+ }
spin_unlock_irqrestore(&qp->s_lock, flags);
-
- /* Call ipath_do_rc_send() in another thread. */
- tasklet_hi_schedule(&qp->s_task);
-
done:
return;
}
@@ -735,7 +766,7 @@ static void reset_psn(struct ipath_qp *qp, u32 psn)
/*
* Set the state to restart in the middle of a request.
* Don't change the s_sge, s_cur_sge, or s_cur_size.
- * See ipath_do_rc_send().
+ * See ipath_make_rc_req().
*/
switch (opcode) {
case IB_WR_SEND:
@@ -771,27 +802,14 @@ done:
*
* The QP s_lock should be held and interrupts disabled.
*/
-void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
+void ipath_restart_rc(struct ipath_qp *qp, u32 psn)
{
struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
struct ipath_ibdev *dev;
if (qp->s_retry == 0) {
- wc->wr_id = wqe->wr.wr_id;
- wc->status = IB_WC_RETRY_EXC_ERR;
- wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc->vendor_err = 0;
- wc->byte_len = 0;
- wc->qp = &qp->ibqp;
- wc->imm_data = 0;
- wc->src_qp = qp->remote_qpn;
- wc->wc_flags = 0;
- wc->pkey_index = 0;
- wc->slid = qp->remote_ah_attr.dlid;
- wc->sl = qp->remote_ah_attr.sl;
- wc->dlid_path_bits = 0;
- wc->port_num = 0;
- ipath_sqerror_qp(qp, wc);
+ ipath_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
+ ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
goto bail;
}
qp->s_retry--;
@@ -804,6 +822,8 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
spin_lock(&dev->pending_lock);
if (!list_empty(&qp->timerwait))
list_del_init(&qp->timerwait);
+ if (!list_empty(&qp->piowait))
+ list_del_init(&qp->piowait);
spin_unlock(&dev->pending_lock);
if (wqe->wr.opcode == IB_WR_RDMA_READ)
@@ -812,7 +832,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
dev->n_rc_resends += (qp->s_psn - psn) & IPATH_PSN_MASK;
reset_psn(qp, psn);
- tasklet_hi_schedule(&qp->s_task);
+ ipath_schedule_send(qp);
bail:
return;
@@ -820,13 +840,7 @@ bail:
static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
{
- if (qp->s_last_psn != psn) {
- qp->s_last_psn = psn;
- if (qp->s_wait_credit) {
- qp->s_wait_credit = 0;
- tasklet_hi_schedule(&qp->s_task);
- }
- }
+ qp->s_last_psn = psn;
}
/**
@@ -845,6 +859,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
+ enum ib_wc_status status;
struct ipath_swqe *wqe;
int ret = 0;
u32 ack_psn;
@@ -909,7 +924,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
*/
update_last_psn(qp, wqe->psn - 1);
/* Retry this request. */
- ipath_restart_rc(qp, wqe->psn, &wc);
+ ipath_restart_rc(qp, wqe->psn);
/*
* No need to process the ACK/NAK since we are
* restarting an earlier request.
@@ -925,32 +940,23 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)) {
qp->s_num_rd_atomic--;
/* Restart sending task if fence is complete */
- if ((qp->s_flags & IPATH_S_FENCE_PENDING) &&
- !qp->s_num_rd_atomic) {
- qp->s_flags &= ~IPATH_S_FENCE_PENDING;
- tasklet_hi_schedule(&qp->s_task);
- } else if (qp->s_flags & IPATH_S_RDMAR_PENDING) {
- qp->s_flags &= ~IPATH_S_RDMAR_PENDING;
- tasklet_hi_schedule(&qp->s_task);
- }
+ if (((qp->s_flags & IPATH_S_FENCE_PENDING) &&
+ !qp->s_num_rd_atomic) ||
+ qp->s_flags & IPATH_S_RDMAR_PENDING)
+ ipath_schedule_send(qp);
}
/* Post a send completion queue entry if requested. */
if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
+ memset(&wc, 0, sizeof wc);
wc.wr_id = wqe->wr.wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.imm_data = 0;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
}
qp->s_retry = qp->s_retry_cnt;
@@ -971,6 +977,8 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
} else {
if (++qp->s_last >= qp->s_size)
qp->s_last = 0;
+ if (qp->state == IB_QPS_SQD && qp->s_last == qp->s_cur)
+ qp->s_draining = 0;
if (qp->s_last == qp->s_tail)
break;
wqe = get_swqe_ptr(qp, qp->s_last);
@@ -994,7 +1002,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
*/
if (ipath_cmp24(qp->s_psn, psn) <= 0) {
reset_psn(qp, psn + 1);
- tasklet_hi_schedule(&qp->s_task);
+ ipath_schedule_send(qp);
}
} else if (ipath_cmp24(qp->s_psn, psn) <= 0) {
qp->s_state = OP(SEND_LAST);
@@ -1012,7 +1020,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
if (qp->s_last == qp->s_tail)
goto bail;
if (qp->s_rnr_retry == 0) {
- wc.status = IB_WC_RNR_RETRY_EXC_ERR;
+ status = IB_WC_RNR_RETRY_EXC_ERR;
goto class_b;
}
if (qp->s_rnr_retry_cnt < 7)
@@ -1033,6 +1041,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
ib_ipath_rnr_table[(aeth >> IPATH_AETH_CREDIT_SHIFT) &
IPATH_AETH_CREDIT_MASK];
ipath_insert_rnr_queue(qp);
+ ipath_schedule_send(qp);
goto bail;
case 3: /* NAK */
@@ -1050,37 +1059,25 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
* RDMA READ response which terminates the RDMA
* READ.
*/
- ipath_restart_rc(qp, psn, &wc);
+ ipath_restart_rc(qp, psn);
break;
case 1: /* Invalid Request */
- wc.status = IB_WC_REM_INV_REQ_ERR;
+ status = IB_WC_REM_INV_REQ_ERR;
dev->n_other_naks++;
goto class_b;
case 2: /* Remote Access Error */
- wc.status = IB_WC_REM_ACCESS_ERR;
+ status = IB_WC_REM_ACCESS_ERR;
dev->n_other_naks++;
goto class_b;
case 3: /* Remote Operation Error */
- wc.status = IB_WC_REM_OP_ERR;
+ status = IB_WC_REM_OP_ERR;
dev->n_other_naks++;
class_b:
- wc.wr_id = wqe->wr.wr_id;
- wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc.vendor_err = 0;
- wc.byte_len = 0;
- wc.qp = &qp->ibqp;
- wc.imm_data = 0;
- wc.src_qp = qp->remote_qpn;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
- wc.slid = qp->remote_ah_attr.dlid;
- wc.sl = qp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- ipath_sqerror_qp(qp, &wc);
+ ipath_send_complete(qp, wqe, status);
+ ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
break;
default:
@@ -1126,8 +1123,8 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
int header_in_data)
{
struct ipath_swqe *wqe;
+ enum ib_wc_status status;
unsigned long flags;
- struct ib_wc wc;
int diff;
u32 pad;
u32 aeth;
@@ -1135,6 +1132,10 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
spin_lock_irqsave(&qp->s_lock, flags);
+ /* Double check we can process this now that we hold the s_lock. */
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
+ goto ack_done;
+
/* Ignore invalid responses. */
if (ipath_cmp24(psn, qp->s_next_psn) >= 0)
goto ack_done;
@@ -1159,6 +1160,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
if (unlikely(qp->s_last == qp->s_tail))
goto ack_done;
wqe = get_swqe_ptr(qp, qp->s_last);
+ status = IB_WC_SUCCESS;
switch (opcode) {
case OP(ACKNOWLEDGE):
@@ -1187,6 +1189,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
wqe = get_swqe_ptr(qp, qp->s_last);
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_op_err;
+ qp->r_flags &= ~IPATH_R_RDMAR_SEQ;
/*
* If this is a response to a resent RDMA read, we
* have to be careful to copy the data to the right
@@ -1200,7 +1203,10 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
/* no AETH, no ACK */
if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
dev->n_rdma_seq++;
- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ if (qp->r_flags & IPATH_R_RDMAR_SEQ)
+ goto ack_done;
+ qp->r_flags |= IPATH_R_RDMAR_SEQ;
+ ipath_restart_rc(qp, qp->s_last_psn + 1);
goto ack_done;
}
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
@@ -1261,7 +1267,10 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
/* ACKs READ req. */
if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
dev->n_rdma_seq++;
- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ if (qp->r_flags & IPATH_R_RDMAR_SEQ)
+ goto ack_done;
+ qp->r_flags |= IPATH_R_RDMAR_SEQ;
+ ipath_restart_rc(qp, qp->s_last_psn + 1);
goto ack_done;
}
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
@@ -1291,31 +1300,16 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto ack_done;
}
-ack_done:
- spin_unlock_irqrestore(&qp->s_lock, flags);
- goto bail;
-
ack_op_err:
- wc.status = IB_WC_LOC_QP_OP_ERR;
+ status = IB_WC_LOC_QP_OP_ERR;
goto ack_err;
ack_len_err:
- wc.status = IB_WC_LOC_LEN_ERR;
+ status = IB_WC_LOC_LEN_ERR;
ack_err:
- wc.wr_id = wqe->wr.wr_id;
- wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc.vendor_err = 0;
- wc.byte_len = 0;
- wc.imm_data = 0;
- wc.qp = &qp->ibqp;
- wc.src_qp = qp->remote_qpn;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
- wc.slid = qp->remote_ah_attr.dlid;
- wc.sl = qp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- ipath_sqerror_qp(qp, &wc);
+ ipath_send_complete(qp, wqe, status);
+ ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+ack_done:
spin_unlock_irqrestore(&qp->s_lock, flags);
bail:
return;
@@ -1384,7 +1378,12 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
psn &= IPATH_PSN_MASK;
e = NULL;
old_req = 1;
+
spin_lock_irqsave(&qp->s_lock, flags);
+ /* Double check we can process this now that we hold the s_lock. */
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
+ goto unlock_done;
+
for (i = qp->r_head_ack_queue; ; i = prev) {
if (i == qp->s_tail_ack_queue)
old_req = 0;
@@ -1512,7 +1511,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
break;
}
qp->r_nak_state = 0;
- tasklet_hi_schedule(&qp->s_task);
+ ipath_schedule_send(qp);
unlock_done:
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -1523,13 +1522,12 @@ send_ack:
return 0;
}
-static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
+void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
{
unsigned long flags;
int lastwqe;
spin_lock_irqsave(&qp->s_lock, flags);
- qp->state = IB_QPS_ERR;
lastwqe = ipath_error_qp(qp, err);
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -1545,18 +1543,15 @@ static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
{
- unsigned long flags;
unsigned next;
next = n + 1;
if (next > IPATH_MAX_RDMA_ATOMIC)
next = 0;
- spin_lock_irqsave(&qp->s_lock, flags);
if (n == qp->s_tail_ack_queue) {
qp->s_tail_ack_queue = next;
qp->s_ack_state = OP(ACKNOWLEDGE);
}
- spin_unlock_irqrestore(&qp->s_lock, flags);
}
/**
@@ -1585,6 +1580,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int diff;
struct ib_reth *reth;
int header_in_data;
+ unsigned long flags;
/* Validate the SLID. See Ch. 9.6.1.5 */
if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
@@ -1643,11 +1639,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
opcode == OP(SEND_LAST) ||
opcode == OP(SEND_LAST_WITH_IMMEDIATE))
break;
- nack_inv:
- ipath_rc_error(qp, IB_WC_REM_INV_REQ_ERR);
- qp->r_nak_state = IB_NAK_INVALID_REQUEST;
- qp->r_ack_psn = qp->r_psn;
- goto send_ack;
+ goto nack_inv;
case OP(RDMA_WRITE_FIRST):
case OP(RDMA_WRITE_MIDDLE):
@@ -1673,18 +1665,13 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
break;
}
- wc.imm_data = 0;
- wc.wc_flags = 0;
+ memset(&wc, 0, sizeof wc);
/* OK, process the packet. */
switch (opcode) {
case OP(SEND_FIRST):
- if (!ipath_get_rwqe(qp, 0)) {
- rnr_nak:
- qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
- qp->r_ack_psn = qp->r_psn;
- goto send_ack;
- }
+ if (!ipath_get_rwqe(qp, 0))
+ goto rnr_nak;
qp->r_rcv_len = 0;
/* FALLTHROUGH */
case OP(SEND_MIDDLE):
@@ -1741,20 +1728,19 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto nack_inv;
ipath_copy_sge(&qp->r_sge, data, tlen);
qp->r_msn++;
- if (!qp->r_wrid_valid)
+ if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags))
break;
- qp->r_wrid_valid = 0;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
- wc.opcode = IB_WC_RECV;
- wc.vendor_err = 0;
+ if (opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE) ||
+ opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+ wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ else
+ wc.opcode = IB_WC_RECV;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
- wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
(ohdr->bth[0] &
@@ -1815,9 +1801,13 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
next = qp->r_head_ack_queue + 1;
if (next > IPATH_MAX_RDMA_ATOMIC)
next = 0;
+ spin_lock_irqsave(&qp->s_lock, flags);
+ /* Double check we can process this while holding the s_lock. */
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
+ goto unlock;
if (unlikely(next == qp->s_tail_ack_queue)) {
if (!qp->s_ack_queue[next].sent)
- goto nack_inv;
+ goto nack_inv_unlck;
ipath_update_ack_queue(qp, next);
}
e = &qp->s_ack_queue[qp->r_head_ack_queue];
@@ -1838,7 +1828,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
ok = ipath_rkey_ok(qp, &e->rdma_sge, len, vaddr,
rkey, IB_ACCESS_REMOTE_READ);
if (unlikely(!ok))
- goto nack_acc;
+ goto nack_acc_unlck;
/*
* Update the next expected PSN. We add 1 later
* below, so only add the remainder here.
@@ -1865,13 +1855,12 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
qp->r_psn++;
qp->r_state = opcode;
qp->r_nak_state = 0;
- barrier();
qp->r_head_ack_queue = next;
- /* Call ipath_do_rc_send() in another thread. */
- tasklet_hi_schedule(&qp->s_task);
+ /* Schedule the send tasklet. */
+ ipath_schedule_send(qp);
- goto done;
+ goto unlock;
}
case OP(COMPARE_SWAP):
@@ -1890,9 +1879,13 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
next = qp->r_head_ack_queue + 1;
if (next > IPATH_MAX_RDMA_ATOMIC)
next = 0;
+ spin_lock_irqsave(&qp->s_lock, flags);
+ /* Double check we can process this while holding the s_lock. */
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
+ goto unlock;
if (unlikely(next == qp->s_tail_ack_queue)) {
if (!qp->s_ack_queue[next].sent)
- goto nack_inv;
+ goto nack_inv_unlck;
ipath_update_ack_queue(qp, next);
}
if (!header_in_data)
@@ -1902,13 +1895,13 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) |
be32_to_cpu(ateth->vaddr[1]);
if (unlikely(vaddr & (sizeof(u64) - 1)))
- goto nack_inv;
+ goto nack_inv_unlck;
rkey = be32_to_cpu(ateth->rkey);
/* Check rkey & NAK */
if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge,
sizeof(u64), vaddr, rkey,
IB_ACCESS_REMOTE_ATOMIC)))
- goto nack_acc;
+ goto nack_acc_unlck;
/* Perform atomic OP and save result. */
maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
sdata = be64_to_cpu(ateth->swap_data);
@@ -1925,13 +1918,12 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
qp->r_psn++;
qp->r_state = opcode;
qp->r_nak_state = 0;
- barrier();
qp->r_head_ack_queue = next;
- /* Call ipath_do_rc_send() in another thread. */
- tasklet_hi_schedule(&qp->s_task);
+ /* Schedule the send tasklet. */
+ ipath_schedule_send(qp);
- goto done;
+ goto unlock;
}
default:
@@ -1947,14 +1939,31 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto send_ack;
goto done;
+rnr_nak:
+ qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
+ qp->r_ack_psn = qp->r_psn;
+ goto send_ack;
+
+nack_inv_unlck:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+nack_inv:
+ ipath_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
+ qp->r_nak_state = IB_NAK_INVALID_REQUEST;
+ qp->r_ack_psn = qp->r_psn;
+ goto send_ack;
+
+nack_acc_unlck:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
nack_acc:
- ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
+ ipath_rc_error(qp, IB_WC_LOC_PROT_ERR);
qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
qp->r_ack_psn = qp->r_psn;
-
send_ack:
send_rc_ack(qp);
+ goto done;
+unlock:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
done:
return;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 8ac5c1d82ccd..a4b5521567fe 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -78,6 +78,7 @@ const u32 ib_ipath_rnr_table[32] = {
* ipath_insert_rnr_queue - put QP on the RNR timeout list for the device
* @qp: the QP
*
+ * Called with the QP s_lock held and interrupts disabled.
* XXX Use a simple list for now. We might need a priority
* queue if we have lots of QPs waiting for RNR timeouts
* but that should be rare.
@@ -85,9 +86,9 @@ const u32 ib_ipath_rnr_table[32] = {
void ipath_insert_rnr_queue(struct ipath_qp *qp)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
- unsigned long flags;
- spin_lock_irqsave(&dev->pending_lock, flags);
+ /* We already did a spin_lock_irqsave(), so just use spin_lock */
+ spin_lock(&dev->pending_lock);
if (list_empty(&dev->rnrwait))
list_add(&qp->timerwait, &dev->rnrwait);
else {
@@ -109,7 +110,7 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
nqp->s_rnr_timeout -= qp->s_rnr_timeout;
list_add(&qp->timerwait, l);
}
- spin_unlock_irqrestore(&dev->pending_lock, flags);
+ spin_unlock(&dev->pending_lock);
}
/**
@@ -140,20 +141,11 @@ int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
goto bail;
bad_lkey:
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr_id;
wc.status = IB_WC_LOC_PROT_ERR;
wc.opcode = IB_WC_RECV;
- wc.vendor_err = 0;
- wc.byte_len = 0;
- wc.imm_data = 0;
wc.qp = &qp->ibqp;
- wc.src_qp = 0;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
- wc.slid = 0;
- wc.sl = 0;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
/* Signal solicited completion event. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
ret = 0;
@@ -194,6 +186,11 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
}
spin_lock_irqsave(&rq->lock, flags);
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
+ ret = 0;
+ goto unlock;
+ }
+
wq = rq->wq;
tail = wq->tail;
/* Validate tail before using it since it is user writable. */
@@ -201,9 +198,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
tail = 0;
do {
if (unlikely(tail == wq->head)) {
- spin_unlock_irqrestore(&rq->lock, flags);
ret = 0;
- goto bail;
+ goto unlock;
}
/* Make sure entry is read after head index is read. */
smp_rmb();
@@ -216,7 +212,7 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
wq->tail = tail;
ret = 1;
- qp->r_wrid_valid = 1;
+ set_bit(IPATH_R_WRID_VALID, &qp->r_aflags);
if (handler) {
u32 n;
@@ -243,8 +239,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
goto bail;
}
}
+unlock:
spin_unlock_irqrestore(&rq->lock, flags);
-
bail:
return ret;
}
@@ -270,38 +266,63 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp)
struct ib_wc wc;
u64 sdata;
atomic64_t *maddr;
+ enum ib_wc_status send_status;
+ /*
+ * Note that we check the responder QP state after
+ * checking the requester's state.
+ */
qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn);
- if (!qp) {
- dev->n_pkt_drops++;
- return;
- }
-again:
spin_lock_irqsave(&sqp->s_lock, flags);
- if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK) ||
- sqp->s_rnr_timeout) {
- spin_unlock_irqrestore(&sqp->s_lock, flags);
- goto done;
- }
+ /* Return if we are already busy processing a work request. */
+ if ((sqp->s_flags & (IPATH_S_BUSY | IPATH_S_ANY_WAIT)) ||
+ !(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_OR_FLUSH_SEND))
+ goto unlock;
- /* Get the next send request. */
- if (sqp->s_last == sqp->s_head) {
- /* Send work queue is empty. */
- spin_unlock_irqrestore(&sqp->s_lock, flags);
- goto done;
+ sqp->s_flags |= IPATH_S_BUSY;
+
+again:
+ if (sqp->s_last == sqp->s_head)
+ goto clr_busy;
+ wqe = get_swqe_ptr(sqp, sqp->s_last);
+
+ /* Return if it is not OK to start a new work reqeust. */
+ if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_NEXT_SEND_OK)) {
+ if (!(ib_ipath_state_ops[sqp->state] & IPATH_FLUSH_SEND))
+ goto clr_busy;
+ /* We are in the error state, flush the work request. */
+ send_status = IB_WC_WR_FLUSH_ERR;
+ goto flush_send;
}
/*
* We can rely on the entry not changing without the s_lock
* being held until we update s_last.
+ * We increment s_cur to indicate s_last is in progress.
*/
- wqe = get_swqe_ptr(sqp, sqp->s_last);
+ if (sqp->s_last == sqp->s_cur) {
+ if (++sqp->s_cur >= sqp->s_size)
+ sqp->s_cur = 0;
+ }
spin_unlock_irqrestore(&sqp->s_lock, flags);
- wc.wc_flags = 0;
- wc.imm_data = 0;
+ if (!qp || !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
+ dev->n_pkt_drops++;
+ /*
+ * For RC, the requester would timeout and retry so
+ * shortcut the timeouts and just signal too many retries.
+ */
+ if (sqp->ibqp.qp_type == IB_QPT_RC)
+ send_status = IB_WC_RETRY_EXC_ERR;
+ else
+ send_status = IB_WC_SUCCESS;
+ goto serr;
+ }
+
+ memset(&wc, 0, sizeof wc);
+ send_status = IB_WC_SUCCESS;
sqp->s_sge.sge = wqe->sg_list[0];
sqp->s_sge.sg_list = wqe->sg_list + 1;
@@ -313,75 +334,33 @@ again:
wc.imm_data = wqe->wr.ex.imm_data;
/* FALLTHROUGH */
case IB_WR_SEND:
- if (!ipath_get_rwqe(qp, 0)) {
- rnr_nak:
- /* Handle RNR NAK */
- if (qp->ibqp.qp_type == IB_QPT_UC)
- goto send_comp;
- if (sqp->s_rnr_retry == 0) {
- wc.status = IB_WC_RNR_RETRY_EXC_ERR;
- goto err;
- }
- if (sqp->s_rnr_retry_cnt < 7)
- sqp->s_rnr_retry--;
- dev->n_rnr_naks++;
- sqp->s_rnr_timeout =
- ib_ipath_rnr_table[qp->r_min_rnr_timer];
- ipath_insert_rnr_queue(sqp);
- goto done;
- }
+ if (!ipath_get_rwqe(qp, 0))
+ goto rnr_nak;
break;
case IB_WR_RDMA_WRITE_WITH_IMM:
- if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_WRITE))) {
- wc.status = IB_WC_REM_INV_REQ_ERR;
- goto err;
- }
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+ goto inv_err;
wc.wc_flags = IB_WC_WITH_IMM;
wc.imm_data = wqe->wr.ex.imm_data;
if (!ipath_get_rwqe(qp, 1))
goto rnr_nak;
/* FALLTHROUGH */
case IB_WR_RDMA_WRITE:
- if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_WRITE))) {
- wc.status = IB_WC_REM_INV_REQ_ERR;
- goto err;
- }
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+ goto inv_err;
if (wqe->length == 0)
break;
if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
- IB_ACCESS_REMOTE_WRITE))) {
- acc_err:
- wc.status = IB_WC_REM_ACCESS_ERR;
- err:
- wc.wr_id = wqe->wr.wr_id;
- wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc.vendor_err = 0;
- wc.byte_len = 0;
- wc.qp = &sqp->ibqp;
- wc.src_qp = sqp->remote_qpn;
- wc.pkey_index = 0;
- wc.slid = sqp->remote_ah_attr.dlid;
- wc.sl = sqp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- spin_lock_irqsave(&sqp->s_lock, flags);
- ipath_sqerror_qp(sqp, &wc);
- spin_unlock_irqrestore(&sqp->s_lock, flags);
- goto done;
- }
+ IB_ACCESS_REMOTE_WRITE)))
+ goto acc_err;
break;
case IB_WR_RDMA_READ:
- if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_READ))) {
- wc.status = IB_WC_REM_INV_REQ_ERR;
- goto err;
- }
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
+ goto inv_err;
if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
@@ -394,11 +373,8 @@ again:
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_ATOMIC))) {
- wc.status = IB_WC_REM_INV_REQ_ERR;
- goto err;
- }
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
+ goto inv_err;
if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
wqe->wr.wr.atomic.remote_addr,
wqe->wr.wr.atomic.rkey,
@@ -415,7 +391,8 @@ again:
goto send_comp;
default:
- goto done;
+ send_status = IB_WC_LOC_QP_OP_ERR;
+ goto serr;
}
sge = &sqp->s_sge.sge;
@@ -448,8 +425,7 @@ again:
sqp->s_len -= len;
}
- if (wqe->wr.opcode == IB_WR_RDMA_WRITE ||
- wqe->wr.opcode == IB_WR_RDMA_READ)
+ if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags))
goto send_comp;
if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
@@ -458,32 +434,89 @@ again:
wc.opcode = IB_WC_RECV;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
- wc.vendor_err = 0;
wc.byte_len = wqe->length;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
- wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
wqe->wr.send_flags & IB_SEND_SOLICITED);
send_comp:
+ spin_lock_irqsave(&sqp->s_lock, flags);
+flush_send:
sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
- ipath_send_complete(sqp, wqe, IB_WC_SUCCESS);
+ ipath_send_complete(sqp, wqe, send_status);
goto again;
+rnr_nak:
+ /* Handle RNR NAK */
+ if (qp->ibqp.qp_type == IB_QPT_UC)
+ goto send_comp;
+ /*
+ * Note: we don't need the s_lock held since the BUSY flag
+ * makes this single threaded.
+ */
+ if (sqp->s_rnr_retry == 0) {
+ send_status = IB_WC_RNR_RETRY_EXC_ERR;
+ goto serr;
+ }
+ if (sqp->s_rnr_retry_cnt < 7)
+ sqp->s_rnr_retry--;
+ spin_lock_irqsave(&sqp->s_lock, flags);
+ if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_RECV_OK))
+ goto clr_busy;
+ sqp->s_flags |= IPATH_S_WAITING;
+ dev->n_rnr_naks++;
+ sqp->s_rnr_timeout = ib_ipath_rnr_table[qp->r_min_rnr_timer];
+ ipath_insert_rnr_queue(sqp);
+ goto clr_busy;
+
+inv_err:
+ send_status = IB_WC_REM_INV_REQ_ERR;
+ wc.status = IB_WC_LOC_QP_OP_ERR;
+ goto err;
+
+acc_err:
+ send_status = IB_WC_REM_ACCESS_ERR;
+ wc.status = IB_WC_LOC_PROT_ERR;
+err:
+ /* responder goes to error state */
+ ipath_rc_error(qp, wc.status);
+
+serr:
+ spin_lock_irqsave(&sqp->s_lock, flags);
+ ipath_send_complete(sqp, wqe, send_status);
+ if (sqp->ibqp.qp_type == IB_QPT_RC) {
+ int lastwqe = ipath_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+
+ sqp->s_flags &= ~IPATH_S_BUSY;
+ spin_unlock_irqrestore(&sqp->s_lock, flags);
+ if (lastwqe) {
+ struct ib_event ev;
+
+ ev.device = sqp->ibqp.device;
+ ev.element.qp = &sqp->ibqp;
+ ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context);
+ }
+ goto done;
+ }
+clr_busy:
+ sqp->s_flags &= ~IPATH_S_BUSY;
+unlock:
+ spin_unlock_irqrestore(&sqp->s_lock, flags);
done:
- if (atomic_dec_and_test(&qp->refcount))
+ if (qp && atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
}
-static void want_buffer(struct ipath_devdata *dd)
+static void want_buffer(struct ipath_devdata *dd, struct ipath_qp *qp)
{
- if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA)) {
+ if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA) ||
+ qp->ibqp.qp_type == IB_QPT_SMI) {
unsigned long flags;
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
@@ -501,26 +534,36 @@ static void want_buffer(struct ipath_devdata *dd)
* @dev: the device we ran out of buffers on
*
* Called when we run out of PIO buffers.
+ * If we are now in the error state, return zero to flush the
+ * send work request.
*/
-static void ipath_no_bufs_available(struct ipath_qp *qp,
+static int ipath_no_bufs_available(struct ipath_qp *qp,
struct ipath_ibdev *dev)
{
unsigned long flags;
+ int ret = 1;
/*
* Note that as soon as want_buffer() is called and
* possibly before it returns, ipath_ib_piobufavail()
- * could be called. If we are still in the tasklet function,
- * tasklet_hi_schedule() will not call us until the next time
- * tasklet_hi_schedule() is called.
- * We leave the busy flag set so that another post send doesn't
- * try to put the same QP on the piowait list again.
+ * could be called. Therefore, put QP on the piowait list before
+ * enabling the PIO avail interrupt.
*/
- spin_lock_irqsave(&dev->pending_lock, flags);
- list_add_tail(&qp->piowait, &dev->piowait);
- spin_unlock_irqrestore(&dev->pending_lock, flags);
- want_buffer(dev->dd);
- dev->n_piowait++;
+ spin_lock_irqsave(&qp->s_lock, flags);
+ if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) {
+ dev->n_piowait++;
+ qp->s_flags |= IPATH_S_WAITING;
+ qp->s_flags &= ~IPATH_S_BUSY;
+ spin_lock(&dev->pending_lock);
+ if (list_empty(&qp->piowait))
+ list_add_tail(&qp->piowait, &dev->piowait);
+ spin_unlock(&dev->pending_lock);
+ } else
+ ret = 0;
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ if (ret)
+ want_buffer(dev->dd, qp);
+ return ret;
}
/**
@@ -596,15 +639,13 @@ void ipath_do_send(unsigned long data)
struct ipath_qp *qp = (struct ipath_qp *)data;
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
int (*make_req)(struct ipath_qp *qp);
-
- if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
- goto bail;
+ unsigned long flags;
if ((qp->ibqp.qp_type == IB_QPT_RC ||
qp->ibqp.qp_type == IB_QPT_UC) &&
qp->remote_ah_attr.dlid == dev->dd->ipath_lid) {
ipath_ruc_loopback(qp);
- goto clear;
+ goto bail;
}
if (qp->ibqp.qp_type == IB_QPT_RC)
@@ -614,6 +655,19 @@ void ipath_do_send(unsigned long data)
else
make_req = ipath_make_ud_req;
+ spin_lock_irqsave(&qp->s_lock, flags);
+
+ /* Return if we are already busy processing a work request. */
+ if ((qp->s_flags & (IPATH_S_BUSY | IPATH_S_ANY_WAIT)) ||
+ !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_OR_FLUSH_SEND)) {
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ goto bail;
+ }
+
+ qp->s_flags |= IPATH_S_BUSY;
+
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+
again:
/* Check for a constructed packet to be sent. */
if (qp->s_hdrwords != 0) {
@@ -623,8 +677,8 @@ again:
*/
if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
qp->s_cur_sge, qp->s_cur_size)) {
- ipath_no_bufs_available(qp, dev);
- goto bail;
+ if (ipath_no_bufs_available(qp, dev))
+ goto bail;
}
dev->n_unicast_xmit++;
/* Record that we sent the packet and s_hdr is empty. */
@@ -633,16 +687,20 @@ again:
if (make_req(qp))
goto again;
-clear:
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
+
bail:;
}
+/*
+ * This should be called with s_lock held.
+ */
void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
enum ib_wc_status status)
{
- unsigned long flags;
- u32 last;
+ u32 old_last, last;
+
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_OR_FLUSH_SEND))
+ return;
/* See ch. 11.2.4.1 and 10.7.3.1 */
if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
@@ -650,27 +708,25 @@ void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
status != IB_WC_SUCCESS) {
struct ib_wc wc;
+ memset(&wc, 0, sizeof wc);
wc.wr_id = wqe->wr.wr_id;
wc.status = status;
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc.vendor_err = 0;
- wc.byte_len = wqe->length;
- wc.imm_data = 0;
wc.qp = &qp->ibqp;
- wc.src_qp = 0;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
- wc.slid = 0;
- wc.sl = 0;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
+ if (status == IB_WC_SUCCESS)
+ wc.byte_len = wqe->length;
+ ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc,
+ status != IB_WC_SUCCESS);
}
- spin_lock_irqsave(&qp->s_lock, flags);
- last = qp->s_last;
+ old_last = last = qp->s_last;
if (++last >= qp->s_size)
last = 0;
qp->s_last = last;
- spin_unlock_irqrestore(&qp->s_lock, flags);
+ if (qp->s_cur == old_last)
+ qp->s_cur = last;
+ if (qp->s_tail == old_last)
+ qp->s_tail = last;
+ if (qp->state == IB_QPS_SQD && last == qp->s_cur)
+ qp->s_draining = 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c
index 1974df7a9f78..3697449c1ba4 100644
--- a/drivers/infiniband/hw/ipath/ipath_sdma.c
+++ b/drivers/infiniband/hw/ipath/ipath_sdma.c
@@ -308,13 +308,15 @@ static void sdma_abort_task(unsigned long opaque)
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
/*
- * Don't restart sdma here. Wait until link is up to ACTIVE.
- * VL15 MADs used to bring the link up use PIO, and multiple
- * link transitions otherwise cause the sdma engine to be
+ * Don't restart sdma here (with the exception
+ * below). Wait until link is up to ACTIVE. VL15 MADs
+ * used to bring the link up use PIO, and multiple link
+ * transitions otherwise cause the sdma engine to be
* stopped and started multiple times.
- * The disable is done here, including the shadow, so the
- * state is kept consistent.
- * See ipath_restart_sdma() for the actual starting of sdma.
+ * The disable is done here, including the shadow,
+ * so the state is kept consistent.
+ * See ipath_restart_sdma() for the actual starting
+ * of sdma.
*/
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
@@ -326,6 +328,13 @@ static void sdma_abort_task(unsigned long opaque)
/* make sure I see next message */
dd->ipath_sdma_abort_jiffies = 0;
+ /*
+ * Not everything that takes SDMA offline is a link
+ * status change. If the link was up, restart SDMA.
+ */
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ ipath_restart_sdma(dd);
+
goto done;
}
@@ -427,7 +436,12 @@ int setup_sdma(struct ipath_devdata *dd)
goto done;
}
- dd->ipath_sdma_status = 0;
+ /*
+ * Set initial status as if we had been up, then gone down.
+ * This lets initial start on transition to ACTIVE be the
+ * same as restart after link flap.
+ */
+ dd->ipath_sdma_status = IPATH_SDMA_ABORT_ABORTED;
dd->ipath_sdma_abort_jiffies = 0;
dd->ipath_sdma_generation = 0;
dd->ipath_sdma_descq_tail = 0;
@@ -449,16 +463,19 @@ int setup_sdma(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmaheadaddr,
dd->ipath_sdma_head_phys);
- /* Reserve all the former "kernel" piobufs */
- n = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - dd->ipath_pioreserved;
- for (i = dd->ipath_lastport_piobuf; i < n; ++i) {
+ /*
+ * Reserve all the former "kernel" piobufs, using high number range
+ * so we get as many 4K buffers as possible
+ */
+ n = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
+ i = dd->ipath_lastport_piobuf + dd->ipath_pioreserved;
+ ipath_chg_pioavailkernel(dd, i, n - i , 0);
+ for (; i < n; ++i) {
unsigned word = i / 64;
unsigned bit = i & 63;
BUG_ON(word >= 3);
senddmabufmask[word] |= 1ULL << bit;
}
- ipath_chg_pioavailkernel(dd, dd->ipath_lastport_piobuf,
- n - dd->ipath_lastport_piobuf, 0);
ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask0,
senddmabufmask[0]);
ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask1,
@@ -615,6 +632,9 @@ void ipath_restart_sdma(struct ipath_devdata *dd)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ /* notify upper layers */
+ ipath_ib_piobufavail(dd->verbs_dev);
+
bail:
return;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index bfe8926b5514..7fd18e833907 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -47,14 +47,30 @@ int ipath_make_uc_req(struct ipath_qp *qp)
{
struct ipath_other_headers *ohdr;
struct ipath_swqe *wqe;
+ unsigned long flags;
u32 hwords;
u32 bth0;
u32 len;
u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
int ret = 0;
- if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))
+ spin_lock_irqsave(&qp->s_lock, flags);
+
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND))
+ goto bail;
+ /* We are in the error state, flush the work request. */
+ if (qp->s_last == qp->s_head)
+ goto bail;
+ /* If DMAs are in progress, we can't flush immediately. */
+ if (atomic_read(&qp->s_dma_busy)) {
+ qp->s_flags |= IPATH_S_WAIT_DMA;
+ goto bail;
+ }
+ wqe = get_swqe_ptr(qp, qp->s_last);
+ ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
goto done;
+ }
ohdr = &qp->s_hdr.u.oth;
if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
@@ -69,9 +85,12 @@ int ipath_make_uc_req(struct ipath_qp *qp)
qp->s_wqe = NULL;
switch (qp->s_state) {
default:
+ if (!(ib_ipath_state_ops[qp->state] &
+ IPATH_PROCESS_NEXT_SEND_OK))
+ goto bail;
/* Check if send work queue is empty. */
if (qp->s_cur == qp->s_head)
- goto done;
+ goto bail;
/*
* Start a new request.
*/
@@ -134,7 +153,7 @@ int ipath_make_uc_req(struct ipath_qp *qp)
break;
default:
- goto done;
+ goto bail;
}
break;
@@ -194,9 +213,14 @@ int ipath_make_uc_req(struct ipath_qp *qp)
ipath_make_ruc_header(to_idev(qp->ibqp.device),
qp, ohdr, bth0 | (qp->s_state << 24),
qp->s_next_psn++ & IPATH_PSN_MASK);
+done:
ret = 1;
+ goto unlock;
-done:
+bail:
+ qp->s_flags &= ~IPATH_S_BUSY;
+unlock:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
return ret;
}
@@ -258,8 +282,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
*/
opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
- wc.imm_data = 0;
- wc.wc_flags = 0;
+ memset(&wc, 0, sizeof wc);
/* Compare the PSN verses the expected PSN. */
if (unlikely(ipath_cmp24(psn, qp->r_psn) != 0)) {
@@ -322,8 +345,8 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
case OP(SEND_ONLY):
case OP(SEND_ONLY_WITH_IMMEDIATE):
send_first:
- if (qp->r_reuse_sge) {
- qp->r_reuse_sge = 0;
+ if (qp->r_flags & IPATH_R_REUSE_SGE) {
+ qp->r_flags &= ~IPATH_R_REUSE_SGE;
qp->r_sge = qp->s_rdma_read_sge;
} else if (!ipath_get_rwqe(qp, 0)) {
dev->n_pkt_drops++;
@@ -340,13 +363,13 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
case OP(SEND_MIDDLE):
/* Check for invalid length PMTU or posted rwqe len. */
if (unlikely(tlen != (hdrsize + pmtu + 4))) {
- qp->r_reuse_sge = 1;
+ qp->r_flags |= IPATH_R_REUSE_SGE;
dev->n_pkt_drops++;
goto done;
}
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len)) {
- qp->r_reuse_sge = 1;
+ qp->r_flags |= IPATH_R_REUSE_SGE;
dev->n_pkt_drops++;
goto done;
}
@@ -372,7 +395,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
/* Check for invalid length. */
/* XXX LAST len should be >= 1 */
if (unlikely(tlen < (hdrsize + pad + 4))) {
- qp->r_reuse_sge = 1;
+ qp->r_flags |= IPATH_R_REUSE_SGE;
dev->n_pkt_drops++;
goto done;
}
@@ -380,7 +403,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
tlen -= (hdrsize + pad + 4);
wc.byte_len = tlen + qp->r_rcv_len;
if (unlikely(wc.byte_len > qp->r_len)) {
- qp->r_reuse_sge = 1;
+ qp->r_flags |= IPATH_R_REUSE_SGE;
dev->n_pkt_drops++;
goto done;
}
@@ -390,14 +413,10 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
- wc.vendor_err = 0;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
- wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
(ohdr->bth[0] &
@@ -488,8 +507,8 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
dev->n_pkt_drops++;
goto done;
}
- if (qp->r_reuse_sge)
- qp->r_reuse_sge = 0;
+ if (qp->r_flags & IPATH_R_REUSE_SGE)
+ qp->r_flags &= ~IPATH_R_REUSE_SGE;
else if (!ipath_get_rwqe(qp, 1)) {
dev->n_pkt_drops++;
goto done;
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 8b6a261c89e3..77ca8ca74e78 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -65,9 +65,9 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
u32 length;
qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn);
- if (!qp) {
+ if (!qp || !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
dev->n_pkt_drops++;
- goto send_comp;
+ goto done;
}
rsge.sg_list = NULL;
@@ -91,14 +91,12 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
* present on the wire.
*/
length = swqe->length;
+ memset(&wc, 0, sizeof wc);
wc.byte_len = length + sizeof(struct ib_grh);
if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
wc.wc_flags = IB_WC_WITH_IMM;
wc.imm_data = swqe->wr.ex.imm_data;
- } else {
- wc.wc_flags = 0;
- wc.imm_data = 0;
}
/*
@@ -229,7 +227,6 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
}
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
- wc.vendor_err = 0;
wc.qp = &qp->ibqp;
wc.src_qp = sqp->ibqp.qp_num;
/* XXX do we know which pkey matched? Only needed for GSI. */
@@ -248,8 +245,7 @@ drop:
kfree(rsge.sg_list);
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
-send_comp:
- ipath_send_complete(sqp, swqe, IB_WC_SUCCESS);
+done:;
}
/**
@@ -264,6 +260,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
struct ipath_other_headers *ohdr;
struct ib_ah_attr *ah_attr;
struct ipath_swqe *wqe;
+ unsigned long flags;
u32 nwords;
u32 extra_bytes;
u32 bth0;
@@ -271,13 +268,30 @@ int ipath_make_ud_req(struct ipath_qp *qp)
u16 lid;
int ret = 0;
- if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)))
- goto bail;
+ spin_lock_irqsave(&qp->s_lock, flags);
+
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_NEXT_SEND_OK)) {
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND))
+ goto bail;
+ /* We are in the error state, flush the work request. */
+ if (qp->s_last == qp->s_head)
+ goto bail;
+ /* If DMAs are in progress, we can't flush immediately. */
+ if (atomic_read(&qp->s_dma_busy)) {
+ qp->s_flags |= IPATH_S_WAIT_DMA;
+ goto bail;
+ }
+ wqe = get_swqe_ptr(qp, qp->s_last);
+ ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+ goto done;
+ }
if (qp->s_cur == qp->s_head)
goto bail;
wqe = get_swqe_ptr(qp, qp->s_cur);
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
/* Construct the header. */
ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
@@ -288,10 +302,23 @@ int ipath_make_ud_req(struct ipath_qp *qp)
dev->n_unicast_xmit++;
} else {
dev->n_unicast_xmit++;
- lid = ah_attr->dlid &
- ~((1 << dev->dd->ipath_lmc) - 1);
+ lid = ah_attr->dlid & ~((1 << dev->dd->ipath_lmc) - 1);
if (unlikely(lid == dev->dd->ipath_lid)) {
+ /*
+ * If DMAs are in progress, we can't generate
+ * a completion for the loopback packet since
+ * it would be out of order.
+ * XXX Instead of waiting, we could queue a
+ * zero length descriptor so we get a callback.
+ */
+ if (atomic_read(&qp->s_dma_busy)) {
+ qp->s_flags |= IPATH_S_WAIT_DMA;
+ goto bail;
+ }
+ spin_unlock_irqrestore(&qp->s_lock, flags);
ipath_ud_loopback(qp, wqe);
+ spin_lock_irqsave(&qp->s_lock, flags);
+ ipath_send_complete(qp, wqe, IB_WC_SUCCESS);
goto done;
}
}
@@ -368,11 +395,13 @@ int ipath_make_ud_req(struct ipath_qp *qp)
ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
done:
- if (++qp->s_cur >= qp->s_size)
- qp->s_cur = 0;
ret = 1;
+ goto unlock;
bail:
+ qp->s_flags &= ~IPATH_S_BUSY;
+unlock:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
return ret;
}
@@ -506,8 +535,8 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
/*
* Get the next work request entry to find where to put the data.
*/
- if (qp->r_reuse_sge)
- qp->r_reuse_sge = 0;
+ if (qp->r_flags & IPATH_R_REUSE_SGE)
+ qp->r_flags &= ~IPATH_R_REUSE_SGE;
else if (!ipath_get_rwqe(qp, 0)) {
/*
* Count VL15 packets dropped due to no receive buffer.
@@ -523,7 +552,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
}
/* Silently drop packets which are too big. */
if (wc.byte_len > qp->r_len) {
- qp->r_reuse_sge = 1;
+ qp->r_flags |= IPATH_R_REUSE_SGE;
dev->n_pkt_drops++;
goto bail;
}
@@ -535,7 +564,8 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh));
ipath_copy_sge(&qp->r_sge, data,
wc.byte_len - sizeof(struct ib_grh));
- qp->r_wrid_valid = 0;
+ if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags))
+ goto bail;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.h b/drivers/infiniband/hw/ipath/ipath_user_sdma.h
index e70946c1428c..fc76316c4a58 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_sdma.h
+++ b/drivers/infiniband/hw/ipath/ipath_user_sdma.h
@@ -45,8 +45,6 @@ int ipath_user_sdma_writev(struct ipath_devdata *dd,
int ipath_user_sdma_make_progress(struct ipath_devdata *dd,
struct ipath_user_sdma_queue *pq);
-int ipath_user_sdma_pkt_sent(const struct ipath_user_sdma_queue *pq,
- u32 counter);
void ipath_user_sdma_queue_drain(struct ipath_devdata *dd,
struct ipath_user_sdma_queue *pq);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index e63927cce5b5..e0ec540042bf 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -111,16 +111,24 @@ static unsigned int ib_ipath_disable_sma;
module_param_named(disable_sma, ib_ipath_disable_sma, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(disable_sma, "Disable the SMA");
+/*
+ * Note that it is OK to post send work requests in the SQE and ERR
+ * states; ipath_do_send() will process them and generate error
+ * completions as per IB 1.2 C10-96.
+ */
const int ib_ipath_state_ops[IB_QPS_ERR + 1] = {
[IB_QPS_RESET] = 0,
[IB_QPS_INIT] = IPATH_POST_RECV_OK,
[IB_QPS_RTR] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK,
[IB_QPS_RTS] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK |
- IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK,
+ IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK |
+ IPATH_PROCESS_NEXT_SEND_OK,
[IB_QPS_SQD] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK |
- IPATH_POST_SEND_OK,
- [IB_QPS_SQE] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK,
- [IB_QPS_ERR] = 0,
+ IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK,
+ [IB_QPS_SQE] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK |
+ IPATH_POST_SEND_OK | IPATH_FLUSH_SEND,
+ [IB_QPS_ERR] = IPATH_POST_RECV_OK | IPATH_FLUSH_RECV |
+ IPATH_POST_SEND_OK | IPATH_FLUSH_SEND,
};
struct ipath_ucontext {
@@ -230,18 +238,6 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
}
}
-static void ipath_flush_wqe(struct ipath_qp *qp, struct ib_send_wr *wr)
-{
- struct ib_wc wc;
-
- memset(&wc, 0, sizeof(wc));
- wc.wr_id = wr->wr_id;
- wc.status = IB_WC_WR_FLUSH_ERR;
- wc.opcode = ib_ipath_wc_opcode[wr->opcode];
- wc.qp = &qp->ibqp;
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
-}
-
/*
* Count the number of DMA descriptors needed to send length bytes of data.
* Don't modify the ipath_sge_state to get the count.
@@ -347,14 +343,8 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
spin_lock_irqsave(&qp->s_lock, flags);
/* Check that state is OK to post send. */
- if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) {
- if (qp->state != IB_QPS_SQE && qp->state != IB_QPS_ERR)
- goto bail_inval;
- /* C10-96 says generate a flushed completion entry. */
- ipath_flush_wqe(qp, wr);
- ret = 0;
- goto bail;
- }
+ if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)))
+ goto bail_inval;
/* IB spec says that num_sge == 0 is OK. */
if (wr->num_sge > qp->s_max_sge)
@@ -396,7 +386,6 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
wqe = get_swqe_ptr(qp, qp->s_head);
wqe->wr = *wr;
- wqe->ssn = qp->s_ssn++;
wqe->length = 0;
if (wr->num_sge) {
acc = wr->opcode >= IB_WR_RDMA_READ ?
@@ -422,6 +411,7 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
goto bail_inval;
} else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
goto bail_inval;
+ wqe->ssn = qp->s_ssn++;
qp->s_head = next;
ret = 0;
@@ -677,6 +667,7 @@ bail:;
static void ipath_ib_timer(struct ipath_ibdev *dev)
{
struct ipath_qp *resend = NULL;
+ struct ipath_qp *rnr = NULL;
struct list_head *last;
struct ipath_qp *qp;
unsigned long flags;
@@ -703,7 +694,9 @@ static void ipath_ib_timer(struct ipath_ibdev *dev)
if (--qp->s_rnr_timeout == 0) {
do {
list_del_init(&qp->timerwait);
- tasklet_hi_schedule(&qp->s_task);
+ qp->timer_next = rnr;
+ rnr = qp;
+ atomic_inc(&qp->refcount);
if (list_empty(last))
break;
qp = list_entry(last->next, struct ipath_qp,
@@ -743,13 +736,15 @@ static void ipath_ib_timer(struct ipath_ibdev *dev)
spin_unlock_irqrestore(&dev->pending_lock, flags);
/* XXX What if timer fires again while this is running? */
- for (qp = resend; qp != NULL; qp = qp->timer_next) {
- struct ib_wc wc;
+ while (resend != NULL) {
+ qp = resend;
+ resend = qp->timer_next;
spin_lock_irqsave(&qp->s_lock, flags);
- if (qp->s_last != qp->s_tail && qp->state == IB_QPS_RTS) {
+ if (qp->s_last != qp->s_tail &&
+ ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) {
dev->n_timeouts++;
- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ ipath_restart_rc(qp, qp->s_last_psn + 1);
}
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -757,6 +752,19 @@ static void ipath_ib_timer(struct ipath_ibdev *dev)
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
}
+ while (rnr != NULL) {
+ qp = rnr;
+ rnr = qp->timer_next;
+
+ spin_lock_irqsave(&qp->s_lock, flags);
+ if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)
+ ipath_schedule_send(qp);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+
+ /* Notify ipath_destroy_qp() if it is waiting. */
+ if (atomic_dec_and_test(&qp->refcount))
+ wake_up(&qp->wait);
+ }
}
static void update_sge(struct ipath_sge_state *ss, u32 length)
@@ -1012,13 +1020,24 @@ static void sdma_complete(void *cookie, int status)
struct ipath_verbs_txreq *tx = cookie;
struct ipath_qp *qp = tx->qp;
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ unsigned int flags;
+ enum ib_wc_status ibs = status == IPATH_SDMA_TXREQ_S_OK ?
+ IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR;
- /* Generate a completion queue entry if needed */
- if (qp->ibqp.qp_type != IB_QPT_RC && tx->wqe) {
- enum ib_wc_status ibs = status == IPATH_SDMA_TXREQ_S_OK ?
- IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR;
-
+ if (atomic_dec_and_test(&qp->s_dma_busy)) {
+ spin_lock_irqsave(&qp->s_lock, flags);
+ if (tx->wqe)
+ ipath_send_complete(qp, tx->wqe, ibs);
+ if ((ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND &&
+ qp->s_last != qp->s_head) ||
+ (qp->s_flags & IPATH_S_WAIT_DMA))
+ ipath_schedule_send(qp);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ wake_up(&qp->wait_dma);
+ } else if (tx->wqe) {
+ spin_lock_irqsave(&qp->s_lock, flags);
ipath_send_complete(qp, tx->wqe, ibs);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
}
if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_FREEBUF)
@@ -1029,6 +1048,21 @@ static void sdma_complete(void *cookie, int status)
wake_up(&qp->wait);
}
+static void decrement_dma_busy(struct ipath_qp *qp)
+{
+ unsigned int flags;
+
+ if (atomic_dec_and_test(&qp->s_dma_busy)) {
+ spin_lock_irqsave(&qp->s_lock, flags);
+ if ((ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND &&
+ qp->s_last != qp->s_head) ||
+ (qp->s_flags & IPATH_S_WAIT_DMA))
+ ipath_schedule_send(qp);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ wake_up(&qp->wait_dma);
+ }
+}
+
/*
* Compute the number of clock cycles of delay before sending the next packet.
* The multipliers reflect the number of clocks for the fastest rate so
@@ -1067,9 +1101,12 @@ static int ipath_verbs_send_dma(struct ipath_qp *qp,
if (tx) {
qp->s_tx = NULL;
/* resend previously constructed packet */
+ atomic_inc(&qp->s_dma_busy);
ret = ipath_sdma_verbs_send(dd, tx->ss, tx->len, tx);
- if (ret)
+ if (ret) {
qp->s_tx = tx;
+ decrement_dma_busy(qp);
+ }
goto bail;
}
@@ -1120,12 +1157,14 @@ static int ipath_verbs_send_dma(struct ipath_qp *qp,
tx->txreq.sg_count = ndesc;
tx->map_len = (hdrwords + 2) << 2;
tx->txreq.map_addr = &tx->hdr;
+ atomic_inc(&qp->s_dma_busy);
ret = ipath_sdma_verbs_send(dd, ss, dwords, tx);
if (ret) {
/* save ss and length in dwords */
tx->ss = ss;
tx->len = dwords;
qp->s_tx = tx;
+ decrement_dma_busy(qp);
}
goto bail;
}
@@ -1146,6 +1185,7 @@ static int ipath_verbs_send_dma(struct ipath_qp *qp,
memcpy(piobuf, hdr, hdrwords << 2);
ipath_copy_from_sge(piobuf + hdrwords, ss, len);
+ atomic_inc(&qp->s_dma_busy);
ret = ipath_sdma_verbs_send(dd, NULL, 0, tx);
/*
* If we couldn't queue the DMA request, save the info
@@ -1156,6 +1196,7 @@ static int ipath_verbs_send_dma(struct ipath_qp *qp,
tx->ss = NULL;
tx->len = 0;
qp->s_tx = tx;
+ decrement_dma_busy(qp);
}
dev->n_unaligned++;
goto bail;
@@ -1179,6 +1220,7 @@ static int ipath_verbs_send_pio(struct ipath_qp *qp,
unsigned flush_wc;
u32 control;
int ret;
+ unsigned int flags;
piobuf = ipath_getpiobuf(dd, plen, NULL);
if (unlikely(piobuf == NULL)) {
@@ -1249,8 +1291,11 @@ static int ipath_verbs_send_pio(struct ipath_qp *qp,
}
copy_io(piobuf, ss, len, flush_wc);
done:
- if (qp->s_wqe)
+ if (qp->s_wqe) {
+ spin_lock_irqsave(&qp->s_lock, flags);
ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ }
ret = 0;
bail:
return ret;
@@ -1283,19 +1328,12 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
* can defer SDMA restart until link goes ACTIVE without
* worrying about just how we got there.
*/
- if (qp->ibqp.qp_type == IB_QPT_SMI)
+ if (qp->ibqp.qp_type == IB_QPT_SMI ||
+ !(dd->ipath_flags & IPATH_HAS_SEND_DMA))
ret = ipath_verbs_send_pio(qp, hdr, hdrwords, ss, len,
plen, dwords);
- /* All non-VL15 packets are dropped if link is not ACTIVE */
- else if (!(dd->ipath_flags & IPATH_LINKACTIVE)) {
- if (qp->s_wqe)
- ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
- ret = 0;
- } else if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
- ret = ipath_verbs_send_dma(qp, hdr, hdrwords, ss, len,
- plen, dwords);
else
- ret = ipath_verbs_send_pio(qp, hdr, hdrwords, ss, len,
+ ret = ipath_verbs_send_dma(qp, hdr, hdrwords, ss, len,
plen, dwords);
return ret;
@@ -1403,27 +1441,46 @@ bail:
* This is called from ipath_intr() at interrupt level when a PIO buffer is
* available after ipath_verbs_send() returned an error that no buffers were
* available. Return 1 if we consumed all the PIO buffers and we still have
- * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and
+ * QPs waiting for buffers (for now, just restart the send tasklet and
* return zero).
*/
int ipath_ib_piobufavail(struct ipath_ibdev *dev)
{
+ struct list_head *list;
+ struct ipath_qp *qplist;
struct ipath_qp *qp;
unsigned long flags;
if (dev == NULL)
goto bail;
+ list = &dev->piowait;
+ qplist = NULL;
+
spin_lock_irqsave(&dev->pending_lock, flags);
- while (!list_empty(&dev->piowait)) {
- qp = list_entry(dev->piowait.next, struct ipath_qp,
- piowait);
+ while (!list_empty(list)) {
+ qp = list_entry(list->next, struct ipath_qp, piowait);
list_del_init(&qp->piowait);
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
- tasklet_hi_schedule(&qp->s_task);
+ qp->pio_next = qplist;
+ qplist = qp;
+ atomic_inc(&qp->refcount);
}
spin_unlock_irqrestore(&dev->pending_lock, flags);
+ while (qplist != NULL) {
+ qp = qplist;
+ qplist = qp->pio_next;
+
+ spin_lock_irqsave(&qp->s_lock, flags);
+ if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)
+ ipath_schedule_send(qp);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+
+ /* Notify ipath_destroy_qp() if it is waiting. */
+ if (atomic_dec_and_test(&qp->refcount))
+ wake_up(&qp->wait);
+ }
+
bail:
return 0;
}
@@ -2145,11 +2202,12 @@ bail:
void ipath_unregister_ib_device(struct ipath_ibdev *dev)
{
struct ib_device *ibdev = &dev->ibdev;
-
- disable_timer(dev->dd);
+ u32 qps_inuse;
ib_unregister_device(ibdev);
+ disable_timer(dev->dd);
+
if (!list_empty(&dev->pending[0]) ||
!list_empty(&dev->pending[1]) ||
!list_empty(&dev->pending[2]))
@@ -2164,7 +2222,10 @@ void ipath_unregister_ib_device(struct ipath_ibdev *dev)
* Note that ipath_unregister_ib_device() can be called before all
* the QPs are destroyed!
*/
- ipath_free_all_qps(&dev->qp_table);
+ qps_inuse = ipath_free_all_qps(&dev->qp_table);
+ if (qps_inuse)
+ ipath_dev_err(dev->dd, "QP memory leak! %u still in use\n",
+ qps_inuse);
kfree(dev->qp_table.table);
kfree(dev->lk_table.table);
kfree(dev->txreq_bufs);
@@ -2215,17 +2276,14 @@ static ssize_t show_stats(struct device *device, struct device_attribute *attr,
"RC OTH NAKs %d\n"
"RC timeouts %d\n"
"RC RDMA dup %d\n"
- "RC stalls %d\n"
"piobuf wait %d\n"
- "no piobuf %d\n"
"unaligned %d\n"
"PKT drops %d\n"
"WQE errs %d\n",
dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks,
dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks,
dev->n_other_naks, dev->n_timeouts,
- dev->n_rdma_dup_busy, dev->n_rc_stalls, dev->n_piowait,
- dev->n_no_piobuf, dev->n_unaligned,
+ dev->n_rdma_dup_busy, dev->n_piowait, dev->n_unaligned,
dev->n_pkt_drops, dev->n_wqe_errs);
for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) {
const struct ipath_opcode_stats *si = &dev->opstats[i];
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 6514aa8306cd..9d12ae8a778e 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -74,6 +74,11 @@
#define IPATH_POST_RECV_OK 0x02
#define IPATH_PROCESS_RECV_OK 0x04
#define IPATH_PROCESS_SEND_OK 0x08
+#define IPATH_PROCESS_NEXT_SEND_OK 0x10
+#define IPATH_FLUSH_SEND 0x20
+#define IPATH_FLUSH_RECV 0x40
+#define IPATH_PROCESS_OR_FLUSH_SEND \
+ (IPATH_PROCESS_SEND_OK | IPATH_FLUSH_SEND)
/* IB Performance Manager status values */
#define IB_PMA_SAMPLE_STATUS_DONE 0x00
@@ -353,12 +358,14 @@ struct ipath_qp {
struct ib_qp ibqp;
struct ipath_qp *next; /* link list for QPN hash table */
struct ipath_qp *timer_next; /* link list for ipath_ib_timer() */
+ struct ipath_qp *pio_next; /* link for ipath_ib_piobufavail() */
struct list_head piowait; /* link for wait PIO buf */
struct list_head timerwait; /* link for waiting for timeouts */
struct ib_ah_attr remote_ah_attr;
struct ipath_ib_header s_hdr; /* next packet header to send */
atomic_t refcount;
wait_queue_head_t wait;
+ wait_queue_head_t wait_dma;
struct tasklet_struct s_task;
struct ipath_mmap_info *ip;
struct ipath_sge_state *s_cur_sge;
@@ -369,7 +376,7 @@ struct ipath_qp {
struct ipath_sge_state s_rdma_read_sge;
struct ipath_sge_state r_sge; /* current receive data */
spinlock_t s_lock;
- unsigned long s_busy;
+ atomic_t s_dma_busy;
u16 s_pkt_delay;
u16 s_hdrwords; /* size of s_hdr in 32 bit words */
u32 s_cur_size; /* size of send packet in bytes */
@@ -383,6 +390,7 @@ struct ipath_qp {
u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */
u32 r_ack_psn; /* PSN for next ACK or atomic ACK */
u64 r_wr_id; /* ID for current receive WQE */
+ unsigned long r_aflags;
u32 r_len; /* total length of r_sge */
u32 r_rcv_len; /* receive data len processed */
u32 r_psn; /* expected rcv packet sequence number */
@@ -394,8 +402,7 @@ struct ipath_qp {
u8 r_state; /* opcode of last packet received */
u8 r_nak_state; /* non-zero if NAK is pending */
u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */
- u8 r_reuse_sge; /* for UC receive errors */
- u8 r_wrid_valid; /* r_wrid set but CQ entry not yet made */
+ u8 r_flags;
u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */
u8 r_head_ack_queue; /* index into s_ack_queue[] */
u8 qp_access_flags;
@@ -404,13 +411,13 @@ struct ipath_qp {
u8 s_rnr_retry_cnt;
u8 s_retry; /* requester retry counter */
u8 s_rnr_retry; /* requester RNR retry counter */
- u8 s_wait_credit; /* limit number of unacked packets sent */
u8 s_pkey_index; /* PKEY index to use */
u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */
u8 s_num_rd_atomic; /* number of RDMA read/atomic pending */
u8 s_tail_ack_queue; /* index into s_ack_queue[] */
u8 s_flags;
u8 s_dmult;
+ u8 s_draining;
u8 timeout; /* Timeout for this QP */
enum ib_mtu path_mtu;
u32 remote_qpn;
@@ -428,16 +435,40 @@ struct ipath_qp {
struct ipath_sge r_sg_list[0]; /* verified SGEs */
};
-/* Bit definition for s_busy. */
-#define IPATH_S_BUSY 0
+/*
+ * Atomic bit definitions for r_aflags.
+ */
+#define IPATH_R_WRID_VALID 0
+
+/*
+ * Bit definitions for r_flags.
+ */
+#define IPATH_R_REUSE_SGE 0x01
+#define IPATH_R_RDMAR_SEQ 0x02
/*
* Bit definitions for s_flags.
+ *
+ * IPATH_S_FENCE_PENDING - waiting for all prior RDMA read or atomic SWQEs
+ * before processing the next SWQE
+ * IPATH_S_RDMAR_PENDING - waiting for any RDMA read or atomic SWQEs
+ * before processing the next SWQE
+ * IPATH_S_WAITING - waiting for RNR timeout or send buffer available.
+ * IPATH_S_WAIT_SSN_CREDIT - waiting for RC credits to process next SWQE
+ * IPATH_S_WAIT_DMA - waiting for send DMA queue to drain before generating
+ * next send completion entry not via send DMA.
*/
#define IPATH_S_SIGNAL_REQ_WR 0x01
#define IPATH_S_FENCE_PENDING 0x02
#define IPATH_S_RDMAR_PENDING 0x04
#define IPATH_S_ACK_PENDING 0x08
+#define IPATH_S_BUSY 0x10
+#define IPATH_S_WAITING 0x20
+#define IPATH_S_WAIT_SSN_CREDIT 0x40
+#define IPATH_S_WAIT_DMA 0x80
+
+#define IPATH_S_ANY_WAIT (IPATH_S_FENCE_PENDING | IPATH_S_RDMAR_PENDING | \
+ IPATH_S_WAITING | IPATH_S_WAIT_SSN_CREDIT | IPATH_S_WAIT_DMA)
#define IPATH_PSN_CREDIT 512
@@ -573,13 +604,11 @@ struct ipath_ibdev {
u32 n_rnr_naks;
u32 n_other_naks;
u32 n_timeouts;
- u32 n_rc_stalls;
u32 n_pkt_drops;
u32 n_vl15_dropped;
u32 n_wqe_errs;
u32 n_rdma_dup_busy;
u32 n_piowait;
- u32 n_no_piobuf;
u32 n_unaligned;
u32 port_cap_flags;
u32 pma_sample_start;
@@ -657,6 +686,17 @@ static inline struct ipath_ibdev *to_idev(struct ib_device *ibdev)
return container_of(ibdev, struct ipath_ibdev, ibdev);
}
+/*
+ * This must be called with s_lock held.
+ */
+static inline void ipath_schedule_send(struct ipath_qp *qp)
+{
+ if (qp->s_flags & IPATH_S_ANY_WAIT)
+ qp->s_flags &= ~IPATH_S_ANY_WAIT;
+ if (!(qp->s_flags & IPATH_S_BUSY))
+ tasklet_hi_schedule(&qp->s_task);
+}
+
int ipath_process_mad(struct ib_device *ibdev,
int mad_flags,
u8 port_num,
@@ -706,12 +746,10 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_qp_init_attr *init_attr);
-void ipath_free_all_qps(struct ipath_qp_table *qpt);
+unsigned ipath_free_all_qps(struct ipath_qp_table *qpt);
int ipath_init_qp_table(struct ipath_ibdev *idev, int size);
-void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc);
-
void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
unsigned ipath_ib_rate_to_mult(enum ib_rate rate);
@@ -729,7 +767,9 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
-void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc);
+void ipath_restart_rc(struct ipath_qp *qp, u32 psn);
+
+void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err);
int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr);
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 5e570bb0bb6f..4521319b1406 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -137,7 +137,7 @@ static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *cont
int err;
*umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe),
- IB_ACCESS_LOCAL_WRITE);
+ IB_ACCESS_LOCAL_WRITE, 1);
if (IS_ERR(*umem))
return PTR_ERR(*umem);
@@ -221,7 +221,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
}
err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
- cq->db.dma, &cq->mcq);
+ cq->db.dma, &cq->mcq, 0);
if (err)
goto err_dbmap;
@@ -246,7 +246,7 @@ err_mtt:
if (context)
ib_umem_release(cq->umem);
else
- mlx4_ib_free_cq_buf(dev, &cq->buf, entries);
+ mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
err_db:
if (!context)
@@ -434,7 +434,7 @@ int mlx4_ib_destroy_cq(struct ib_cq *cq)
mlx4_ib_db_unmap_user(to_mucontext(cq->uobject->context), &mcq->db);
ib_umem_release(mcq->umem);
} else {
- mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe + 1);
+ mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe);
mlx4_db_free(dev->dev, &mcq->db);
}
diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c
index 8e342cc9baec..8aee4233b388 100644
--- a/drivers/infiniband/hw/mlx4/doorbell.c
+++ b/drivers/infiniband/hw/mlx4/doorbell.c
@@ -63,7 +63,7 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
page->user_virt = (virt & PAGE_MASK);
page->refcnt = 0;
page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
- PAGE_SIZE, 0);
+ PAGE_SIZE, 0, 0);
if (IS_ERR(page->umem)) {
err = PTR_ERR(page->umem);
kfree(page);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index fe2c2e94a5f8..68e92485fc76 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -132,7 +132,8 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (!mr)
return ERR_PTR(-ENOMEM);
- mr->umem = ib_umem_get(pd->uobject->context, start, length, access_flags);
+ mr->umem = ib_umem_get(pd->uobject->context, start, length,
+ access_flags, 0);
if (IS_ERR(mr->umem)) {
err = PTR_ERR(mr->umem);
goto err_free;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 80ea8b9e7761..8e02ecfec188 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -482,7 +482,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
goto err;
qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
- qp->buf_size, 0);
+ qp->buf_size, 0, 0);
if (IS_ERR(qp->umem)) {
err = PTR_ERR(qp->umem);
goto err;
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 204619702f9d..12d6bc6f8007 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -109,7 +109,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
}
srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
- buf_size, 0);
+ buf_size, 0, 0);
if (IS_ERR(srq->umem)) {
err = PTR_ERR(srq->umem);
goto err_srq;
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 3538da16e3fe..820205dec560 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -818,15 +818,9 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
{
- u32 key;
-
if (!fmr->maps)
return;
- key = tavor_key_to_hw_index(fmr->ibmr.lkey);
- key &= dev->limits.num_mpts - 1;
- fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);
-
fmr->maps = 0;
writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);
@@ -834,16 +828,9 @@ void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
{
- u32 key;
-
if (!fmr->maps)
return;
- key = arbel_key_to_hw_index(fmr->ibmr.lkey);
- key &= dev->limits.num_mpts - 1;
- key = adjust_key(dev, key);
- fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
-
fmr->maps = 0;
*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 696e1f302332..be34f99ca625 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -39,6 +39,8 @@
#include <rdma/ib_smi.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_user_verbs.h>
+
+#include <linux/sched.h>
#include <linux/mm.h>
#include "mthca_dev.h"
@@ -367,6 +369,8 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev,
return ERR_PTR(-EFAULT);
}
+ context->reg_mr_warned = 0;
+
return &context->ibucontext;
}
@@ -1006,17 +1010,31 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
struct mthca_dev *dev = to_mdev(pd->device);
struct ib_umem_chunk *chunk;
struct mthca_mr *mr;
+ struct mthca_reg_mr ucmd;
u64 *pages;
int shift, n, len;
int i, j, k;
int err = 0;
int write_mtt_size;
+ if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) {
+ if (!to_mucontext(pd->uobject->context)->reg_mr_warned) {
+ mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n",
+ current->comm);
+ mthca_warn(dev, " Update libmthca to fix this.\n");
+ }
+ ++to_mucontext(pd->uobject->context)->reg_mr_warned;
+ ucmd.mr_attrs = 0;
+ } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return ERR_PTR(-EFAULT);
+
mr = kmalloc(sizeof *mr, GFP_KERNEL);
if (!mr)
return ERR_PTR(-ENOMEM);
- mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+ mr->umem = ib_umem_get(pd->uobject->context, start, length, acc,
+ ucmd.mr_attrs & MTHCA_MR_DMASYNC);
+
if (IS_ERR(mr->umem)) {
err = PTR_ERR(mr->umem);
goto err;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 262616c8ebb6..934bf9544037 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -67,6 +67,7 @@ struct mthca_ucontext {
struct ib_ucontext ibucontext;
struct mthca_uar uar;
struct mthca_user_db_table *db_tab;
+ int reg_mr_warned;
};
struct mthca_mtt;
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
index 02cc0a766f3a..e1262c942db8 100644
--- a/drivers/infiniband/hw/mthca/mthca_user.h
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -61,6 +61,16 @@ struct mthca_alloc_pd_resp {
__u32 reserved;
};
+struct mthca_reg_mr {
+/*
+ * Mark the memory region with a DMA attribute that causes
+ * in-flight DMA to be flushed when the region is written to:
+ */
+#define MTHCA_MR_DMASYNC 0x1
+ __u32 mr_attrs;
+ __u32 reserved;
+};
+
struct mthca_create_cq {
__u32 lkey;
__u32 pdn;
diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig
index 2aeb7ac972a9..d449eb6ec78e 100644
--- a/drivers/infiniband/hw/nes/Kconfig
+++ b/drivers/infiniband/hw/nes/Kconfig
@@ -2,6 +2,7 @@ config INFINIBAND_NES
tristate "NetEffect RNIC Driver"
depends on PCI && INET && INFINIBAND
select LIBCRC32C
+ select INET_LRO
---help---
This is a low-level driver for NetEffect RDMA enabled
Network Interface Cards (RNIC).
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index cdf2e9ad62f7..61b46e9c7d2d 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -535,8 +535,8 @@ int nes_register_ofa_device(struct nes_ib_device *);
int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *);
void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16);
void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *);
-void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16);
-void nes_read_10G_phy_reg(struct nes_device *, u16, u8);
+void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16, u16);
+void nes_read_10G_phy_reg(struct nes_device *, u8, u8, u16);
struct nes_cqp_request *nes_get_cqp_request(struct nes_device *);
void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int);
int nes_arp_table(struct nes_device *, u32, u8 *, u32);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index d940fc27129a..9a4b40fae40d 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -594,7 +594,7 @@ static void nes_cm_timer_tick(unsigned long pass)
continue;
}
/* this seems like the correct place, but leave send entry unprotected */
- // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */
atomic_inc(&send_entry->skb->users);
cm_packets_retrans++;
nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p,"
@@ -1335,7 +1335,7 @@ static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
cm_node->loc_addr, cm_node->loc_port,
cm_node->rem_addr, cm_node->rem_port,
cm_node->state, atomic_read(&cm_node->ref_count));
- // create event
+ /* create event */
cm_node->state = NES_CM_STATE_CLOSED;
create_event(cm_node, NES_CM_EVENT_ABORTED);
@@ -1669,7 +1669,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
if (!cm_node)
return NULL;
- // set our node side to client (active) side
+ /* set our node side to client (active) side */
cm_node->tcp_cntxt.client = 1;
cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
@@ -1694,7 +1694,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
loopbackremotenode->mpa_frame_size = mpa_frame_size -
sizeof(struct ietf_mpa_frame);
- // we are done handling this state, set node to a TSA state
+ /* we are done handling this state, set node to a TSA state */
cm_node->state = NES_CM_STATE_TSA;
cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num;
loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num;
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 08964cc7e98a..d3278f111ca7 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -38,9 +38,14 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
#include "nes.h"
+static unsigned int nes_lro_max_aggr = NES_LRO_MAX_AGGR;
+module_param(nes_lro_max_aggr, uint, 0444);
+MODULE_PARM_DESC(nes_lro_max_aggr, "NIC LRO max packet aggregation");
+
static u32 crit_err_count;
u32 int_mod_timer_init;
u32 int_mod_cq_depth_256;
@@ -832,7 +837,7 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou
nes_write_indexed(nesdev, 0x00000900, 0x20000001);
nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
- //
+
nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
/* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
@@ -1207,11 +1212,16 @@ int nes_init_phy(struct nes_device *nesdev)
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter = 0;
+ u32 sds_common_control0;
u32 mac_index = nesdev->mac_index;
- u32 tx_config;
+ u32 tx_config = 0;
u16 phy_data;
+ u32 temp_phy_data = 0;
+ u32 temp_phy_data2 = 0;
+ u32 i = 0;
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
printk(PFX "%s: Programming mdc config for 1G\n", __func__);
@@ -1223,7 +1233,7 @@ int nes_init_phy(struct nes_device *nesdev)
nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n",
nesadapter->phy_index[mac_index], phy_data);
- nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
+ nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
/* Reset the PHY */
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
@@ -1277,12 +1287,126 @@ int nes_init_phy(struct nes_device *nesdev)
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
} else {
- if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+ if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) ||
+ (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
/* setup 10G MDIO operation */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config |= 0x14;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
+ if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ mdelay(10);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+ temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+
+ /*
+ * if firmware is already running (like from a
+ * driver un-load/load, don't do anything.
+ */
+ if (temp_phy_data == temp_phy_data2) {
+ /* configure QT2505 AMCC PHY */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0x0000, 0x8000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc302, 0x0044);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc318, 0x0052);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528);
+
+ /*
+ * remove micro from reset; chip boots from ROM,
+ * uploads EEPROM f/w image, uC executes f/w
+ */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0002);
+
+ /*
+ * wait for heart beat to start to
+ * know loading is done
+ */
+ counter = 0;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if (counter++ > 1000) {
+ nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from heartbeat check <this is bad!!!> \n");
+ break;
+ }
+ mdelay(100);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+ temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ } while ((temp_phy_data2 == temp_phy_data));
+
+ /*
+ * wait for tracking to start to know
+ * f/w is good to go
+ */
+ counter = 0;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7fd);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if (counter++ > 1000) {
+ nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from status check <this is bad!!!> \n");
+ break;
+ }
+ mdelay(1000);
+ /*
+ * nes_debug(NES_DBG_PHY, "AMCC PHY- phy_status not ready yet = 0x%02X\n",
+ * temp_phy_data);
+ */
+ } while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70));
+
+ /* set LOS Control invert RXLOSB_I_PADINV */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd003, 0x0000);
+ /* set LOS Control to mask of RXLOSB_I */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc314, 0x0042);
+ /* set LED1 to input mode (LED1 and LED2 share same LED) */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd006, 0x0007);
+ /* set LED2 to RX link_status and activity */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd007, 0x000A);
+ /* set LED3 to RX link_status */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd008, 0x0009);
+
+ /*
+ * reset the res-calibration on t2
+ * serdes; ensures it is stable after
+ * the amcc phy is stable
+ */
+
+ sds_common_control0 = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0);
+ sds_common_control0 |= 0x1;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0);
+
+ /* release the res-calibration reset */
+ sds_common_control0 &= 0xfffffffe;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0);
+
+ i = 0;
+ while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
+ && (i++ < 5000)) {
+ /* mdelay(1); */
+ }
+
+ /*
+ * wait for link train done before moving on,
+ * or will get an interupt storm
+ */
+ counter = 0;
+ do {
+ temp_phy_data = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200 * (nesdev->mac_index & 1)));
+ if (counter++ > 1000) {
+ nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from link train wait <this is bad, link didnt train!!!>\n");
+ break;
+ }
+ mdelay(1);
+ } while (((temp_phy_data & 0x0f1f0000) != 0x0f0f0000));
+ }
+ }
}
return 0;
}
@@ -1375,6 +1499,25 @@ static void nes_rq_wqes_timeout(unsigned long parm)
}
+static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr,
+ void **tcph, u64 *hdr_flags, void *priv)
+{
+ unsigned int ip_len;
+ struct iphdr *iph;
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return -1;
+ ip_len = ip_hdrlen(skb);
+ skb_set_transport_header(skb, ip_len);
+ *tcph = tcp_hdr(skb);
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *iphdr = iph;
+ return 0;
+}
+
+
/**
* nes_init_nic_qp
*/
@@ -1520,10 +1663,10 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
}
u64temp = (u64)nesvnic->nic.sq_pbase;
- nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
u64temp = (u64)nesvnic->nic.rq_pbase;
- nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
@@ -1575,7 +1718,7 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
nic_rqe = &nesvnic->nic.rq_vbase[counter];
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
nesvnic->nic.rx_skb[counter] = skb;
}
@@ -1592,15 +1735,21 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
-
if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
{
nes_nic_init_timer(nesdev);
if (netdev->mtu > 1500)
jumbomode = 1;
- nes_nic_init_timer_defaults(nesdev, jumbomode);
- }
-
+ nes_nic_init_timer_defaults(nesdev, jumbomode);
+ }
+ nesvnic->lro_mgr.max_aggr = nes_lro_max_aggr;
+ nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS;
+ nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc;
+ nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr;
+ nesvnic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+ nesvnic->lro_mgr.dev = netdev;
+ nesvnic->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+ nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
return 0;
}
@@ -1620,8 +1769,8 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
/* Free remaining NIC receive buffers */
while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
- nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
- wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+ nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
+ wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
@@ -1704,17 +1853,17 @@ int nes_napi_isr(struct nes_device *nesdev)
/* iff NIC, process here, else wait for DPC */
if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
nesdev->napi_isr_ran = 0;
- nes_write32(nesdev->regs+NES_INT_STAT,
- (int_stat &
- ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+ nes_write32(nesdev->regs + NES_INT_STAT,
+ (int_stat &
+ ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3)));
/* Process the CEQs */
nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
- (!nesadapter->et_use_adaptive_rx_coalesce)) ||
- ((nesadapter->et_use_adaptive_rx_coalesce) &&
- (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) {
+ (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+ ((nesadapter->et_use_adaptive_rx_coalesce) &&
+ (nesdev->deepcq_count > nesadapter->et_pkt_rate_low))))) {
if ((nesdev->int_req & NES_INT_TIMER) == 0) {
/* Enable Periodic timer interrupts */
nesdev->int_req |= NES_INT_TIMER;
@@ -1792,12 +1941,12 @@ void nes_dpc(unsigned long param)
}
if (int_stat) {
- if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
+ if (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2 | NES_INT_MAC3)) {
/* Ack the interrupts */
nes_write32(nesdev->regs+NES_INT_STAT,
- (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+ (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0|
+ NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3)));
}
temp_int_stat = int_stat;
@@ -1862,8 +2011,8 @@ void nes_dpc(unsigned long param)
}
}
/* Don't use the interface interrupt bit stay in loop */
- int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
+ int_stat &= ~NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 |
+ NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3;
} while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
if (timer_ints == 1) {
@@ -1874,9 +2023,9 @@ void nes_dpc(unsigned long param)
nesdev->timer_only_int_count = 0;
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
- nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ nes_write32(nesdev->regs + NES_INT_MASK, ~nesdev->int_req);
} else {
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
}
} else {
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
@@ -1884,7 +2033,7 @@ void nes_dpc(unsigned long param)
nes_nic_init_timer(nesdev);
}
nesdev->timer_only_int_count = 0;
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
}
} else {
nesdev->timer_only_int_count = 0;
@@ -1933,7 +2082,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
do {
if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
NES_CEQE_VALID) {
- u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) |
+ u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]))) << 32) |
((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
u64temp <<= 1;
cq = *((struct nes_hw_cq **)&u64temp);
@@ -1961,7 +2110,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
*/
static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
{
-// u64 u64temp;
+ /* u64 u64temp; */
u32 head;
u32 aeq_size;
u32 aeqe_misc;
@@ -1980,8 +2129,10 @@ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
if (aeqe_cq_id >= NES_FIRST_QPN) {
/* dealing with an accelerated QP related AE */
-// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) |
-// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+ /*
+ * u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]))) << 32) |
+ * ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+ */
nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
} else {
/* TODO: dealing with a CQP related AE */
@@ -2081,6 +2232,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
u32 u32temp;
u16 phy_data;
u16 temp_phy_data;
+ u32 pcs_val = 0x0f0f0000;
+ u32 pcs_mask = 0x0f1f0000;
spin_lock_irqsave(&nesadapter->phy_lock, flags);
if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
@@ -2144,13 +2297,30 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+
+ if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_PUMA_1G) {
+ switch (mac_index) {
+ case 1:
+ case 3:
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+ break;
+ default:
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ break;
+ }
+ } else {
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200));
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200));
+ }
+
nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
mac_index, pcs_control_status);
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
u32temp = 0x01010000;
if (nesadapter->port_count > 2) {
u32temp |= 0x02020000;
@@ -2159,24 +2329,59 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
phy_data = 0;
nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
}
- } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
- nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
- temp_phy_data = (u16)nes_read_indexed(nesdev,
- NES_IDX_MAC_MDIO_CONTROL);
- u32temp = 20;
- do {
- nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
- phy_data = (u16)nes_read_indexed(nesdev,
- NES_IDX_MAC_MDIO_CONTROL);
- if ((phy_data == temp_phy_data) || (!(--u32temp)))
- break;
- temp_phy_data = phy_data;
- } while (1);
- nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
- __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
-
} else {
- phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
+ switch (nesadapter->phy_type[mac_index]) {
+ case NES_PHY_TYPE_IRIS:
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ u32temp = 20;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+ phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if ((phy_data == temp_phy_data) || (!(--u32temp)))
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+ nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+ __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
+ break;
+
+ case NES_PHY_TYPE_ARGUS:
+ /* clear the alarms */
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc002);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc005);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc006);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005);
+ /* check link status */
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ u32temp = 100;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+
+ phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if ((phy_data == temp_phy_data) || (!(--u32temp)))
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+ nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+ __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
+ break;
+
+ case NES_PHY_TYPE_PUMA_1G:
+ if (mac_index < 2)
+ pcs_val = pcs_mask = 0x01010000;
+ else
+ pcs_val = pcs_mask = 0x02020000;
+ /* fall through */
+ default:
+ phy_data = (pcs_val == (pcs_control_status & pcs_mask)) ? 0x4 : 0x0;
+ break;
+ }
}
if (phy_data & 0x0004) {
@@ -2185,8 +2390,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n",
nesvnic->linkup);
if (nesvnic->linkup == 0) {
- printk(PFX "The Link is now up for port %u, netdev %p.\n",
- mac_index, nesvnic->netdev);
+ printk(PFX "The Link is now up for port %s, netdev %p.\n",
+ nesvnic->netdev->name, nesvnic->netdev);
if (netif_queue_stopped(nesvnic->netdev))
netif_start_queue(nesvnic->netdev);
nesvnic->linkup = 1;
@@ -2199,8 +2404,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n",
nesvnic->linkup);
if (nesvnic->linkup == 1) {
- printk(PFX "The Link is now down for port %u, netdev %p.\n",
- mac_index, nesvnic->netdev);
+ printk(PFX "The Link is now down for port %s, netdev %p.\n",
+ nesvnic->netdev->name, nesvnic->netdev);
if (!(netif_queue_stopped(nesvnic->netdev)))
netif_stop_queue(nesvnic->netdev);
nesvnic->linkup = 0;
@@ -2254,10 +2459,13 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
u16 pkt_type;
u16 rqes_processed = 0;
u8 sq_cqes = 0;
+ u8 nes_use_lro = 0;
head = cq->cq_head;
cq_size = cq->cq_size;
cq->cqes_pending = 1;
+ if (nesvnic->netdev->features & NETIF_F_LRO)
+ nes_use_lro = 1;
do {
if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
NES_NIC_CQE_VALID) {
@@ -2272,8 +2480,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
/* bump past the vlan tag */
wqe_fragment_length++;
if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
- u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
- u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+ u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX +
+ wqe_fragment_index * 2]);
+ u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX +
+ wqe_fragment_index * 2])) << 32;
bus_address = (dma_addr_t)u64temp;
if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) {
pci_unmap_single(nesdev->pcidev,
@@ -2283,8 +2493,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
}
for (; wqe_fragment_index < 5; wqe_fragment_index++) {
if (wqe_fragment_length[wqe_fragment_index]) {
- u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
- u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+ u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX +
+ wqe_fragment_index * 2]);
+ u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
+ + wqe_fragment_index * 2])) <<32;
bus_address = (dma_addr_t)u64temp;
pci_unmap_page(nesdev->pcidev,
bus_address,
@@ -2331,7 +2543,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) {
nes_write32(nesdev->regs+NES_CQE_ALLOC,
cq->cq_number | (cqe_count << 16));
-// nesadapter->tune_timer.cq_count += cqe_count;
+ /* nesadapter->tune_timer.cq_count += cqe_count; */
nesdev->currcq_count += cqe_count;
cqe_count = 0;
nes_replenish_nic_rq(nesvnic);
@@ -2379,9 +2591,16 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
>> 16);
nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
nesvnic->netdev->name, vlan_tag);
- nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
+ if (nes_use_lro)
+ lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb,
+ nesvnic->vlan_grp, vlan_tag, NULL);
+ else
+ nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
} else {
- nes_netif_rx(rx_skb);
+ if (nes_use_lro)
+ lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
+ else
+ nes_netif_rx(rx_skb);
}
}
@@ -2399,7 +2618,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
/* Replenish Nic CQ */
nes_write32(nesdev->regs+NES_CQE_ALLOC,
cq->cq_number | (cqe_count << 16));
-// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+ /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */
nesdev->currcq_count += cqe_count;
cqe_count = 0;
}
@@ -2413,26 +2632,27 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
} while (1);
+ if (nes_use_lro)
+ lro_flush_all(&nesvnic->lro_mgr);
if (sq_cqes) {
barrier();
/* restart the queue if it had been stopped */
if (netif_queue_stopped(nesvnic->netdev))
netif_wake_queue(nesvnic->netdev);
}
-
cq->cq_head = head;
/* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
cq->cq_number, cqe_count, cq->cq_head); */
cq->cqe_allocs_pending = cqe_count;
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
{
-// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+ /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */
nesdev->currcq_count += cqe_count;
nes_nic_tune_timer(nesdev);
}
if (atomic_read(&nesvnic->rx_skbs_needed))
nes_replenish_nic_rq(nesvnic);
- }
+}
/**
@@ -2461,7 +2681,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head].
- cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+ cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) |
((u64)(le32_to_cpu(cq->cq_vbase[head].
cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX])));
cqp = *((struct nes_hw_cqp **)&u64temp);
@@ -2478,7 +2698,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
}
u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
- wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) |
+ wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) |
((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX])));
cqp_request = *((struct nes_cqp_request **)&u64temp);
@@ -2515,7 +2735,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
} else {
nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
cqp_request,
- le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
+ le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]) & 0x3f);
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
@@ -2529,7 +2749,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
}
cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
- nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16));
+ nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (1 << 16));
if (++cqp->sq_tail >= cqp->sq_size)
cqp->sq_tail = 0;
@@ -2598,13 +2818,13 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nes_debug(NES_DBG_AEQ, "\n");
aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) {
- context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+ context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
} else {
aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
- aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN];
BUG_ON(!context);
}
@@ -2617,7 +2837,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
-
switch (async_event_id) {
case NES_AEQE_AEID_LLP_FIN_RECEIVED:
nesqp = *((struct nes_qp **)&context);
@@ -3021,7 +3240,7 @@ void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID);
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32(
(((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
- (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
+ (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
(((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]);
} else {
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 8f36e231bdf5..745bf94f3f07 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -33,8 +33,12 @@
#ifndef __NES_HW_H
#define __NES_HW_H
-#define NES_PHY_TYPE_1G 2
-#define NES_PHY_TYPE_IRIS 3
+#include <linux/inet_lro.h>
+
+#define NES_PHY_TYPE_1G 2
+#define NES_PHY_TYPE_IRIS 3
+#define NES_PHY_TYPE_ARGUS 4
+#define NES_PHY_TYPE_PUMA_1G 5
#define NES_PHY_TYPE_PUMA_10G 6
#define NES_MULTICAST_PF_MAX 8
@@ -965,7 +969,7 @@ struct nes_arp_entry {
#define NES_NIC_CQ_DOWNWARD_TREND 16
struct nes_hw_tune_timer {
- //u16 cq_count;
+ /* u16 cq_count; */
u16 threshold_low;
u16 threshold_target;
u16 threshold_high;
@@ -982,8 +986,10 @@ struct nes_hw_tune_timer {
#define NES_TIMER_INT_LIMIT 2
#define NES_TIMER_INT_LIMIT_DYNAMIC 10
#define NES_TIMER_ENABLE_LIMIT 4
-#define NES_MAX_LINK_INTERRUPTS 128
-#define NES_MAX_LINK_CHECK 200
+#define NES_MAX_LINK_INTERRUPTS 128
+#define NES_MAX_LINK_CHECK 200
+#define NES_MAX_LRO_DESCRIPTORS 32
+#define NES_LRO_MAX_AGGR 64
struct nes_adapter {
u64 fw_ver;
@@ -1183,6 +1189,9 @@ struct nes_vnic {
u8 of_device_registered;
u8 rdma_enabled;
u8 rx_checksum_disabled;
+ u32 lro_max_aggr;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS];
};
struct nes_ib_device {
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index e5366b013c1a..1b0938c87774 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -185,12 +185,13 @@ static int nes_netdev_open(struct net_device *netdev)
nic_active |= nic_active_bit;
nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
- macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
macaddr_high += (u16)netdev->dev_addr[1];
- macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
- macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
- macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
- macaddr_low += (u32)netdev->dev_addr[5];
+
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
/* Program the various MAC regs */
for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
@@ -451,7 +452,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
__le16 *wqe_fragment_length;
u32 nr_frags;
u32 original_first_length;
-// u64 *wqe_fragment_address;
+ /* u64 *wqe_fragment_address; */
/* first fragment (0) is used by copy buffer */
u16 wqe_fragment_index=1;
u16 hoffset;
@@ -461,11 +462,12 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
u32 old_head;
u32 wqe_misc;
- /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
- " (%u frags), tso_size=%u\n",
- netdev->name, skb->len, skb_headlen(skb),
- skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
- */
+ /*
+ * nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
+ * " (%u frags), tso_size=%u\n",
+ * netdev->name, skb->len, skb_headlen(skb),
+ * skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
+ */
if (!netif_carrier_ok(netdev))
return NETDEV_TX_OK;
@@ -795,12 +797,12 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
printk(PFX "%s: Address length = %d, Address = %s\n",
__func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data));
- macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
macaddr_high += (u16)netdev->dev_addr[1];
- macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
- macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
- macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
- macaddr_low += (u32)netdev->dev_addr[5];
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
if (nesvnic->qp_nic_index[i] == 0xf) {
@@ -881,12 +883,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
print_mac(mac, multicast_addr->dmi_addr),
perfect_filter_register_address+(mc_index * 8),
mc_nic_index);
- macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
+ macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
macaddr_high += (u16)multicast_addr->dmi_addr[1];
- macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
- macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
- macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
- macaddr_low += (u32)multicast_addr->dmi_addr[5];
+ macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
+ macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
+ macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
+ macaddr_low += (u32)multicast_addr->dmi_addr[5];
nes_write_indexed(nesdev,
perfect_filter_register_address+(mc_index * 8),
macaddr_low);
@@ -910,23 +912,23 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
/**
* nes_netdev_change_mtu
*/
-static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
+static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- int ret = 0;
- u8 jumbomode=0;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ int ret = 0;
+ u8 jumbomode = 0;
- if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
+ if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
return -EINVAL;
- netdev->mtu = new_mtu;
+ netdev->mtu = new_mtu;
nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN;
if (netdev->mtu > 1500) {
jumbomode=1;
}
- nes_nic_init_timer_defaults(nesdev, jumbomode);
+ nes_nic_init_timer_defaults(nesdev, jumbomode);
if (netif_running(netdev)) {
nes_netdev_stop(netdev);
@@ -936,8 +938,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
return ret;
}
-#define NES_ETHTOOL_STAT_COUNT 55
-static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = {
+static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
"Link Change Interrupts",
"Linearized SKBs",
"T/GSO Requests",
@@ -993,8 +994,12 @@ static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN]
"CQ Depth 32",
"CQ Depth 128",
"CQ Depth 256",
+ "LRO aggregated",
+ "LRO flushed",
+ "LRO no_desc",
};
+#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset)
/**
* nes_netdev_get_rx_csum
@@ -1189,6 +1194,9 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
target_stat_values[52] = int_mod_cq_depth_32;
target_stat_values[53] = int_mod_cq_depth_128;
target_stat_values[54] = int_mod_cq_depth_256;
+ target_stat_values[55] = nesvnic->lro_mgr.stats.aggregated;
+ target_stat_values[56] = nesvnic->lro_mgr.stats.flushed;
+ target_stat_values[57] = nesvnic->lro_mgr.stats.no_desc;
}
@@ -1219,14 +1227,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *et_coalesce)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
unsigned long flags;
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
if (et_coalesce->rx_max_coalesced_frames_low) {
- shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low;
+ shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low;
}
if (et_coalesce->rx_max_coalesced_frames_irq) {
shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq;
@@ -1246,14 +1254,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev,
nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq;
if (et_coalesce->use_adaptive_rx_coalesce) {
nesadapter->et_use_adaptive_rx_coalesce = 1;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
nesadapter->et_rx_coalesce_usecs_irq = 0;
if (et_coalesce->pkt_rate_low) {
- nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low;
+ nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low;
}
} else {
nesadapter->et_use_adaptive_rx_coalesce = 0;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
if (nesadapter->et_rx_coalesce_usecs_irq) {
nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8)));
@@ -1270,28 +1278,28 @@ static int nes_netdev_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *et_coalesce)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct ethtool_coalesce temp_et_coalesce;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
unsigned long flags;
memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce));
- temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
- temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce;
- temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
+ temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
+ temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce;
+ temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low;
spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
- temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low;
- temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target;
+ temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low;
+ temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target;
temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high;
- temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
+ temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max;
if (nesadapter->et_use_adaptive_rx_coalesce) {
temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use;
}
spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
- memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
+ memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
return 0;
}
@@ -1370,30 +1378,38 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd
u16 phy_data;
et_cmd->duplex = DUPLEX_FULL;
- et_cmd->port = PORT_MII;
+ et_cmd->port = PORT_MII;
+
if (nesadapter->OneG_Mode) {
- et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg;
- et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg;
et_cmd->speed = SPEED_1000;
- nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
- &phy_data);
- if (phy_data&0x1000) {
- et_cmd->autoneg = AUTONEG_ENABLE;
+ if (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) {
+ et_cmd->supported = SUPPORTED_1000baseT_Full;
+ et_cmd->advertising = ADVERTISED_1000baseT_Full;
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ et_cmd->transceiver = XCVR_INTERNAL;
+ et_cmd->phy_address = nesdev->mac_index;
} else {
- et_cmd->autoneg = AUTONEG_DISABLE;
+ et_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg;
+ et_cmd->advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg;
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data);
+ if (phy_data & 0x1000)
+ et_cmd->autoneg = AUTONEG_ENABLE;
+ else
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ et_cmd->transceiver = XCVR_EXTERNAL;
+ et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
}
- et_cmd->transceiver = XCVR_EXTERNAL;
- et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
} else {
- if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+ if ((nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) ||
+ (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_ARGUS)) {
et_cmd->transceiver = XCVR_EXTERNAL;
- et_cmd->port = PORT_FIBRE;
- et_cmd->supported = SUPPORTED_FIBRE;
+ et_cmd->port = PORT_FIBRE;
+ et_cmd->supported = SUPPORTED_FIBRE;
et_cmd->advertising = ADVERTISED_FIBRE;
et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
} else {
et_cmd->transceiver = XCVR_INTERNAL;
- et_cmd->supported = SUPPORTED_10000baseT_Full;
+ et_cmd->supported = SUPPORTED_10000baseT_Full;
et_cmd->advertising = ADVERTISED_10000baseT_Full;
et_cmd->phy_address = nesdev->mac_index;
}
@@ -1416,14 +1432,15 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd
struct nes_adapter *nesadapter = nesdev->nesadapter;
u16 phy_data;
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G)) {
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
&phy_data);
if (et_cmd->autoneg) {
/* Turn on Full duplex, Autoneg, and restart autonegotiation */
phy_data |= 0x1300;
} else {
- // Turn off autoneg
+ /* Turn off autoneg */
phy_data &= ~0x1000;
}
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
@@ -1454,6 +1471,8 @@ static struct ethtool_ops nes_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
};
@@ -1607,27 +1626,34 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
if ((nesdev->netdev_count == 0) &&
- (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
- nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
- NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1)));
+ ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) ||
+ ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) &&
+ (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||
+ ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {
+ /*
+ * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
+ * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1)));
+ */
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200*(nesvnic->logical_port&1)));
- u32temp |= 0x00200000;
- nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200*(nesvnic->logical_port&1)), u32temp);
+ (0x200 * (nesdev->mac_index & 1)));
+ if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) {
+ u32temp |= 0x00200000;
+ nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200 * (nesdev->mac_index & 1)), u32temp);
+ }
+
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200*(nesvnic->logical_port&1)) );
+ (0x200 * (nesdev->mac_index & 1)));
+
if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
- if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+ if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) {
nes_init_phy(nesdev);
- nes_read_10G_phy_reg(nesdev, 1,
- nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+ nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
temp_phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
u32temp = 20;
do {
- nes_read_10G_phy_reg(nesdev, 1,
- nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+ nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
if ((phy_data == temp_phy_data) || (!(--u32temp)))
@@ -1644,6 +1670,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
nesvnic->linkup = 1;
}
+ } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) {
+ nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n",
+ nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn));
+ if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) ||
+ ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) {
+ nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
+ nesvnic->linkup = 1;
+ }
}
/* clear the MAC interrupt status, assumes direct logical to physical mapping */
u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index c6d5631a6995..fe83d1b2b177 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -444,15 +444,13 @@ void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16
/**
* nes_write_10G_phy_reg
*/
-void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg,
- u8 phy_addr, u16 data)
+void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_addr, u8 dev_addr, u16 phy_reg,
+ u16 data)
{
- u32 dev_addr;
u32 port_addr;
u32 u32temp;
u32 counter;
- dev_addr = 1;
port_addr = phy_addr;
/* set address */
@@ -492,14 +490,12 @@ void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg,
* This routine only issues the read, the data must be read
* separately.
*/
-void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr)
+void nes_read_10G_phy_reg(struct nes_device *nesdev, u8 phy_addr, u8 dev_addr, u16 phy_reg)
{
- u32 dev_addr;
u32 port_addr;
u32 u32temp;
u32 counter;
- dev_addr = 1;
port_addr = phy_addr;
/* set address */
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index ee74f7c7a6da..99b3c4ae86eb 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1266,7 +1266,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
sq_size = init_attr->cap.max_send_wr;
rq_size = init_attr->cap.max_recv_wr;
- // check if the encoded sizes are OK or not...
+ /* check if the encoded sizes are OK or not... */
sq_encoded_size = nes_get_encoded_size(&sq_size);
rq_encoded_size = nes_get_encoded_size(&rq_size);
@@ -2377,7 +2377,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
u8 single_page = 1;
u8 stag_key;
- region = ib_umem_get(pd->uobject->context, start, length, acc);
+ region = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(region)) {
return (struct ib_mr *)region;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index f1f142dc64b1..ca126fc2b853 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -95,6 +95,8 @@ enum {
IPOIB_MCAST_FLAG_SENDONLY = 1,
IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */
IPOIB_MCAST_FLAG_ATTACHED = 3,
+
+ MAX_SEND_CQE = 16,
};
#define IPOIB_OP_RECV (1ul << 31)
@@ -285,7 +287,8 @@ struct ipoib_dev_priv {
u16 pkey_index;
struct ib_pd *pd;
struct ib_mr *mr;
- struct ib_cq *cq;
+ struct ib_cq *recv_cq;
+ struct ib_cq *send_cq;
struct ib_qp *qp;
u32 qkey;
@@ -305,6 +308,7 @@ struct ipoib_dev_priv {
struct ib_sge tx_sge[MAX_SKB_FRAGS + 1];
struct ib_send_wr tx_wr;
unsigned tx_outstanding;
+ struct ib_wc send_wc[MAX_SEND_CQE];
struct ib_recv_wr rx_wr;
struct ib_sge rx_sge[IPOIB_UD_RX_SG];
@@ -330,6 +334,7 @@ struct ipoib_dev_priv {
#endif
int hca_caps;
struct ipoib_ethtool_st ethtool;
+ struct timer_list poll_timer;
};
struct ipoib_ah {
@@ -400,6 +405,7 @@ extern struct workqueue_struct *ipoib_workqueue;
int ipoib_poll(struct napi_struct *napi, int budget);
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
+void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr);
struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
struct ib_pd *pd, struct ib_ah_attr *attr);
@@ -662,7 +668,6 @@ static inline int ipoib_register_debugfs(void) { return 0; }
static inline void ipoib_unregister_debugfs(void) { }
#endif
-
#define ipoib_printk(level, priv, format, arg...) \
printk(level "%s: " format, ((struct ipoib_dev_priv *) priv)->dev->name , ## arg)
#define ipoib_warn(priv, format, arg...) \
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 9db7b0bd9134..97e67d36378f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -249,8 +249,8 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_init_attr attr = {
.event_handler = ipoib_cm_rx_event_handler,
- .send_cq = priv->cq, /* For drain WR */
- .recv_cq = priv->cq,
+ .send_cq = priv->recv_cq, /* For drain WR */
+ .recv_cq = priv->recv_cq,
.srq = priv->cm.srq,
.cap.max_send_wr = 1, /* For drain WR */
.cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */
@@ -951,8 +951,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_init_attr attr = {
- .send_cq = priv->cq,
- .recv_cq = priv->cq,
+ .send_cq = priv->recv_cq,
+ .recv_cq = priv->recv_cq,
.srq = priv->cm.srq,
.cap.max_send_wr = ipoib_sendq_size,
.cap.max_send_sge = 1,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 9a47428366c9..10279b79c44d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -71,7 +71,7 @@ static int ipoib_set_coalesce(struct net_device *dev,
coal->rx_max_coalesced_frames > 0xffff)
return -EINVAL;
- ret = ib_modify_cq(priv->cq, coal->rx_max_coalesced_frames,
+ ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames,
coal->rx_coalesce_usecs);
if (ret && ret != -ENOSYS) {
ipoib_warn(priv, "failed modifying CQ (%d)\n", ret);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 7cf1fa7074ab..f429bce24c20 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -364,7 +364,6 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, 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, "send completion: id %d, status: %d\n",
wr_id, wc->status);
@@ -384,13 +383,11 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
dev_kfree_skb_any(tx_req->skb);
- spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_tail;
if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
netif_queue_stopped(dev) &&
test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
netif_wake_queue(dev);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
if (wc->status != IB_WC_SUCCESS &&
wc->status != IB_WC_WR_FLUSH_ERR)
@@ -399,6 +396,17 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
wc->status, wr_id, wc->vendor_err);
}
+static int poll_tx(struct ipoib_dev_priv *priv)
+{
+ int n, i;
+
+ n = ib_poll_cq(priv->send_cq, MAX_SEND_CQE, priv->send_wc);
+ for (i = 0; i < n; ++i)
+ ipoib_ib_handle_tx_wc(priv->dev, priv->send_wc + i);
+
+ return n == MAX_SEND_CQE;
+}
+
int ipoib_poll(struct napi_struct *napi, int budget)
{
struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi);
@@ -414,7 +422,7 @@ poll_more:
int max = (budget - done);
t = min(IPOIB_NUM_WC, max);
- n = ib_poll_cq(priv->cq, t, priv->ibwc);
+ n = ib_poll_cq(priv->recv_cq, t, priv->ibwc);
for (i = 0; i < n; i++) {
struct ib_wc *wc = priv->ibwc + i;
@@ -425,12 +433,8 @@ poll_more:
ipoib_cm_handle_rx_wc(dev, wc);
else
ipoib_ib_handle_rx_wc(dev, wc);
- } else {
- if (wc->wr_id & IPOIB_OP_CM)
- ipoib_cm_handle_tx_wc(dev, wc);
- else
- ipoib_ib_handle_tx_wc(dev, wc);
- }
+ } else
+ ipoib_cm_handle_tx_wc(priv->dev, wc);
}
if (n != t)
@@ -439,7 +443,7 @@ poll_more:
if (done < budget) {
netif_rx_complete(dev, napi);
- if (unlikely(ib_req_notify_cq(priv->cq,
+ if (unlikely(ib_req_notify_cq(priv->recv_cq,
IB_CQ_NEXT_COMP |
IB_CQ_REPORT_MISSED_EVENTS)) &&
netif_rx_reschedule(dev, napi))
@@ -457,6 +461,26 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
netif_rx_schedule(dev, &priv->napi);
}
+static void drain_tx_cq(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ while (poll_tx(priv))
+ ; /* nothing */
+
+ if (netif_queue_stopped(dev))
+ mod_timer(&priv->poll_timer, jiffies + 1);
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+}
+
+void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr)
+{
+ drain_tx_cq((struct net_device *)dev_ptr);
+}
+
static inline int post_send(struct ipoib_dev_priv *priv,
unsigned int wr_id,
struct ib_ah *address, u32 qpn,
@@ -551,23 +575,34 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
else
priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
+ if (++priv->tx_outstanding == ipoib_sendq_size) {
+ ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
+ if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP))
+ ipoib_warn(priv, "request notify on send CQ failed\n");
+ netif_stop_queue(dev);
+ }
+
if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
address->ah, qpn, tx_req, phead, hlen))) {
ipoib_warn(priv, "post_send failed\n");
++dev->stats.tx_errors;
+ --priv->tx_outstanding;
ipoib_dma_unmap_tx(priv->ca, tx_req);
dev_kfree_skb_any(skb);
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
} else {
dev->trans_start = jiffies;
address->last_send = priv->tx_head;
++priv->tx_head;
+ skb_orphan(skb);
- if (++priv->tx_outstanding == ipoib_sendq_size) {
- ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
- netif_stop_queue(dev);
- }
}
+
+ if (unlikely(priv->tx_outstanding > MAX_SEND_CQE))
+ while (poll_tx(priv))
+ ; /* nothing */
}
static void __ipoib_reap_ah(struct net_device *dev)
@@ -601,6 +636,11 @@ void ipoib_reap_ah(struct work_struct *work)
round_jiffies_relative(HZ));
}
+static void ipoib_ib_tx_timer_func(unsigned long ctx)
+{
+ drain_tx_cq((struct net_device *)ctx);
+}
+
int ipoib_ib_dev_open(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -637,6 +677,10 @@ int ipoib_ib_dev_open(struct net_device *dev)
queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
round_jiffies_relative(HZ));
+ init_timer(&priv->poll_timer);
+ priv->poll_timer.function = ipoib_ib_tx_timer_func;
+ priv->poll_timer.data = (unsigned long)dev;
+
set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
return 0;
@@ -714,7 +758,7 @@ void ipoib_drain_cq(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev);
int i, n;
do {
- n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
+ n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc);
for (i = 0; i < n; ++i) {
/*
* Convert any successful completions to flush
@@ -729,14 +773,13 @@ void ipoib_drain_cq(struct net_device *dev)
ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
else
ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
- } else {
- if (priv->ibwc[i].wr_id & IPOIB_OP_CM)
- ipoib_cm_handle_tx_wc(dev, priv->ibwc + i);
- else
- ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
- }
+ } else
+ ipoib_cm_handle_tx_wc(dev, priv->ibwc + i);
}
} while (n == IPOIB_NUM_WC);
+
+ while (poll_tx(priv))
+ ; /* nothing */
}
int ipoib_ib_dev_stop(struct net_device *dev, int flush)
@@ -803,6 +846,7 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
ipoib_dbg(priv, "All sends and receives done.\n");
timeout:
+ del_timer_sync(&priv->poll_timer);
qp_attr.qp_state = IB_QPS_RESET;
if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE))
ipoib_warn(priv, "Failed to modify QP to RESET state\n");
@@ -826,7 +870,7 @@ timeout:
msleep(1);
}
- ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
+ ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP);
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 7a4ed9d3d844..2442090ac8d1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1298,7 +1298,8 @@ static int __init ipoib_init_module(void)
ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
- ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
+ ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE,
+ IPOIB_MIN_QUEUE_SIZE));
#ifdef CONFIG_INFINIBAND_IPOIB_CM
ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
#endif
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 07c03f178a49..8766d29ce3b7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -171,26 +171,34 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
goto out_free_pd;
}
- size = ipoib_sendq_size + ipoib_recvq_size + 1;
+ size = ipoib_recvq_size + 1;
ret = ipoib_cm_dev_init(dev);
if (!ret) {
+ size += ipoib_sendq_size;
if (ipoib_cm_has_srq(dev))
size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
else
size += ipoib_recvq_size * ipoib_max_conn_qp;
}
- priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
- if (IS_ERR(priv->cq)) {
- printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
+ priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
+ if (IS_ERR(priv->recv_cq)) {
+ printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name);
goto out_free_mr;
}
- if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP))
- goto out_free_cq;
+ priv->send_cq = ib_create_cq(priv->ca, ipoib_send_comp_handler, NULL,
+ dev, ipoib_sendq_size, 0);
+ if (IS_ERR(priv->send_cq)) {
+ printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name);
+ goto out_free_recv_cq;
+ }
+
+ if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP))
+ goto out_free_send_cq;
- init_attr.send_cq = priv->cq;
- init_attr.recv_cq = priv->cq;
+ init_attr.send_cq = priv->send_cq;
+ init_attr.recv_cq = priv->recv_cq;
if (priv->hca_caps & IB_DEVICE_UD_TSO)
init_attr.create_flags = IB_QP_CREATE_IPOIB_UD_LSO;
@@ -201,7 +209,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
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_cq;
+ goto out_free_send_cq;
}
priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff;
@@ -230,8 +238,11 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
return 0;
-out_free_cq:
- ib_destroy_cq(priv->cq);
+out_free_send_cq:
+ ib_destroy_cq(priv->send_cq);
+
+out_free_recv_cq:
+ ib_destroy_cq(priv->recv_cq);
out_free_mr:
ib_dereg_mr(priv->mr);
@@ -254,8 +265,11 @@ void ipoib_transport_dev_cleanup(struct net_device *dev)
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
}
- if (ib_destroy_cq(priv->cq))
- ipoib_warn(priv, "ib_cq_destroy failed\n");
+ if (ib_destroy_cq(priv->send_cq))
+ ipoib_warn(priv, "ib_cq_destroy (send) failed\n");
+
+ if (ib_destroy_cq(priv->recv_cq))
+ ipoib_warn(priv, "ib_cq_destroy (recv) failed\n");
ipoib_cm_dev_cleanup(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 431fdeaa2dc4..1cdb5cfb0ff1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -90,6 +90,9 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
}
priv->max_ib_mtu = ppriv->max_ib_mtu;
+ /* MTU will be reset when mcast join happens */
+ priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu);
+ priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu;
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
priv->pkey = pkey;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index be1b9fbd416d..aeb58cae9a3f 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -473,13 +473,15 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s
stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */
stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
- stats->custom_length = 3;
+ stats->custom_length = 4;
strcpy(stats->custom[0].desc, "qp_tx_queue_full");
stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */
strcpy(stats->custom[1].desc, "fmr_map_not_avail");
stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */;
strcpy(stats->custom[2].desc, "eh_abort_cnt");
stats->custom[2].value = conn->eh_abort_cnt;
+ strcpy(stats->custom[3].desc, "fmr_unalign_cnt");
+ stats->custom[3].value = conn->fmr_unalign_cnt;
}
static int
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 1ee867b1b341..a8c1b300e34d 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -71,6 +71,13 @@
#define iser_dbg(fmt, arg...) \
do { \
+ if (iser_debug_level > 1) \
+ printk(KERN_DEBUG PFX "%s:" fmt,\
+ __func__ , ## arg); \
+ } while (0)
+
+#define iser_warn(fmt, arg...) \
+ do { \
if (iser_debug_level > 0) \
printk(KERN_DEBUG PFX "%s:" fmt,\
__func__ , ## arg); \
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 4a17743a639f..cac50c4dc159 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -334,8 +334,11 @@ static void iser_data_buf_dump(struct iser_data_buf *data,
struct scatterlist *sg;
int i;
+ if (iser_debug_level == 0)
+ return;
+
for_each_sg(sgl, sg, data->dma_nents, i)
- iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
+ iser_warn("sg[%d] dma_addr:0x%lX page:0x%p "
"off:0x%x sz:0x%x dma_len:0x%x\n",
i, (unsigned long)ib_sg_dma_address(ibdev, sg),
sg_page(sg), sg->offset,
@@ -420,6 +423,7 @@ void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
enum iser_data_dir cmd_dir)
{
+ struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn;
struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
struct ib_device *ibdev = device->ib_device;
@@ -434,7 +438,8 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
aligned_len = iser_data_buf_aligned_len(mem, ibdev);
if (aligned_len != mem->dma_nents) {
- iser_err("rdma alignment violation %d/%d aligned\n",
+ iscsi_conn->fmr_unalign_cnt++;
+ iser_warn("rdma alignment violation %d/%d aligned\n",
aligned_len, mem->size);
iser_data_buf_dump(mem, ibdev);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index f02c242c3114..27006fc18305 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -898,30 +898,26 @@ static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
- proc_bus_input_dir = proc_mkdir("input", proc_bus);
+ proc_bus_input_dir = proc_mkdir("bus/input", NULL);
if (!proc_bus_input_dir)
return -ENOMEM;
proc_bus_input_dir->owner = THIS_MODULE;
- entry = create_proc_entry("devices", 0, proc_bus_input_dir);
+ entry = proc_create("devices", 0, proc_bus_input_dir,
+ &input_devices_fileops);
if (!entry)
goto fail1;
- entry->owner = THIS_MODULE;
- entry->proc_fops = &input_devices_fileops;
-
- entry = create_proc_entry("handlers", 0, proc_bus_input_dir);
+ entry = proc_create("handlers", 0, proc_bus_input_dir,
+ &input_handlers_fileops);
if (!entry)
goto fail2;
- entry->owner = THIS_MODULE;
- entry->proc_fops = &input_handlers_fileops;
-
return 0;
fail2: remove_proc_entry("devices", proc_bus_input_dir);
- fail1: remove_proc_entry("input", proc_bus);
+ fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}
@@ -929,7 +925,7 @@ static void input_proc_exit(void)
{
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
- remove_proc_entry("input", proc_bus);
+ remove_proc_entry("bus/input", NULL);
}
#else /* !CONFIG_PROC_FS */
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 50d80ecf0b80..aacf71f3cd44 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -217,6 +217,10 @@ hil_keyb_init(void)
return -ENOMEM;
#if defined(CONFIG_HP300)
+ if (!MACH_IS_HP300) {
+ err = -ENODEV;
+ goto err1;
+ }
if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
printk(KERN_ERR "HIL: hardware register was not found\n");
err = -ENODEV;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 92b683411d5a..3ad8bd9f7543 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -14,7 +14,7 @@ if INPUT_MISC
config INPUT_PCSPKR
tristate "PC Speaker support"
- depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
+ depends on PCSPKR_PLATFORM
depends on SND_PCSP=n
help
Say Y here if you want the standard PC Speaker to be used for
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index ab76ea442fa5..45e5d05b01de 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -691,6 +691,11 @@ static int __init hp_sdc_rtc_init(void)
{
int ret;
+#ifdef __mc68000__
+ if (!MACH_IS_HP300)
+ return -ENODEV;
+#endif
+
init_MUTEX(&i8042tregs);
if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 02b3ad8c0826..edfedd9a166c 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -69,6 +69,7 @@
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/hil.h>
+#include <linux/semaphore.h>
#include <asm/io.h>
#include <asm/system.h>
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index f1fd3b638a37..587398f5c9df 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -306,6 +306,11 @@ static int __init hp_sdc_mlc_init(void)
{
hil_mlc *mlc = &hp_sdc_mlc;
+#ifdef __mc68000__
+ if (!MACH_IS_HP300)
+ return -ENODEV;
+#endif
+
printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n");
hp_sdc_mlc_priv.emtestmode = 0;
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index 3b4e13b9ce1b..f451c7351a9d 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -25,7 +25,7 @@
#elif defined(__arm__)
/* defined in include/asm-arm/arch-xxx/irqs.h */
#include <asm/irq.h>
-#elif defined(CONFIG_SUPERH64)
+#elif defined(CONFIG_SH_CAYMAN)
#include <asm/irq.h>
#else
# define I8042_KBD_IRQ 1
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index cb89aff2e160..d962a8d78b14 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -156,7 +156,7 @@ static int __init q40kbd_init(void)
int error;
if (!MACH_IS_Q40)
- return -EIO;
+ return -ENODEV;
error = platform_driver_register(&q40kbd_driver);
if (error)
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index e1a3a79ab3f9..7ff71ba7b7c9 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -46,7 +46,7 @@ struct serport {
static int serport_serio_write(struct serio *serio, unsigned char data)
{
struct serport *serport = serio->port_data;
- return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
+ return -(serport->tty->ops->write(serport->tty, &data, 1) != 1);
}
static int serport_serio_open(struct serio *serio)
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 1d759f6f8076..55c1134d6137 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -528,9 +528,9 @@ static void aiptek_irq(struct urb *urb)
(aiptek->curSetting.pointerMode)) {
aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
} else {
- x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
- y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
- z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
+ x = get_unaligned_le16(data + 1);
+ y = get_unaligned_le16(data + 3);
+ z = get_unaligned_le16(data + 6);
dv = (data[5] & 0x01) != 0 ? 1 : 0;
p = (data[5] & 0x02) != 0 ? 1 : 0;
@@ -613,8 +613,8 @@ static void aiptek_irq(struct urb *urb)
(aiptek->curSetting.pointerMode)) {
aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
} else {
- x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
- y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+ x = get_unaligned_le16(data + 1);
+ y = get_unaligned_le16(data + 3);
jitterable = data[5] & 0x1c;
@@ -679,7 +679,7 @@ static void aiptek_irq(struct urb *urb)
pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1;
- z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
+ z = get_unaligned_le16(data + 4);
if (dv) {
/* If the selected tool changed, reset the old
@@ -757,7 +757,7 @@ static void aiptek_irq(struct urb *urb)
* hat switches (which just so happen to be the macroKeys.)
*/
else if (data[0] == 6) {
- macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+ macro = get_unaligned_le16(data + 1);
if (macro > 0) {
input_report_key(inputdev, macroKeyEvents[macro - 1],
0);
@@ -952,7 +952,7 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
buf[0], buf[1], buf[2]);
ret = -EIO;
} else {
- ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1)));
+ ret = get_unaligned_le16(buf + 1);
}
kfree(buf);
return ret;
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index f66ca215cdec..c5a8661a1baa 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -245,11 +245,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
data = report[i];
break;
case 2:
- data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));
+ data16 = get_unaligned_le16(&report[i]);
break;
case 3:
size = 4;
- data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));
+ data32 = get_unaligned_le32(&report[i]);
break;
}
@@ -695,10 +695,10 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* 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]));
+ val = get_unaligned_le16(&device->buffer[1]);
input_report_abs(inputdev, ABS_X, val);
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+ val = get_unaligned_le16(&device->buffer[3]);
input_report_abs(inputdev, ABS_Y, val);
/* Ditto for proximity bit */
@@ -762,7 +762,7 @@ static void gtco_urb_callback(struct urb *urbinfo)
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));
+ val = get_unaligned_le16(le_buffer);
input_report_abs(inputdev, ABS_Y, val);
/*
@@ -772,10 +772,10 @@ static void gtco_urb_callback(struct urb *urbinfo)
buttonbyte = device->buffer[5] >> 1;
} else {
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+ val = get_unaligned_le16(&device->buffer[1]);
input_report_abs(inputdev, ABS_X, val);
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+ val = get_unaligned_le16(&device->buffer[3]);
input_report_abs(inputdev, ABS_Y, val);
buttonbyte = device->buffer[5];
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 1182fc133167..f23f5a97fb38 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -63,8 +63,8 @@ static void kbtab_irq(struct urb *urb)
goto exit;
}
- kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1]));
- kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3]));
+ kbtab->x = get_unaligned_le16(&data[1]);
+ kbtab->y = get_unaligned_le16(&data[3]);
kbtab->pressure = (data[5]);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 24c6b7ca62be..6ca0bb949ad3 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1111,11 +1111,12 @@ static int capinc_tty_write(struct tty_struct * tty,
return count;
}
-static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+static int 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;
+ int ret = 1;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
@@ -1125,7 +1126,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
#endif
- return;
+ return 0;
}
spin_lock_irqsave(&workaround_lock, flags);
@@ -1134,7 +1135,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
if (skb_tailroom(skb) > 0) {
*(skb_put(skb, 1)) = ch;
spin_unlock_irqrestore(&workaround_lock, flags);
- return;
+ return 1;
}
mp->ttyskb = NULL;
skb_queue_tail(&mp->outqueue, skb);
@@ -1148,8 +1149,10 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
mp->ttyskb = skb;
} else {
printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+ ret = 0;
}
spin_unlock_irqrestore(&workaround_lock, flags);
+ return ret;
}
static void capinc_tty_flush_chars(struct tty_struct *tty)
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index 845a797b0030..c29208bd7521 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -114,6 +114,7 @@ static int seq_contrstats_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_controller_ops = {
+ .owner = THIS_MODULE,
.open = seq_controller_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -121,6 +122,7 @@ static const struct file_operations proc_controller_ops = {
};
static const struct file_operations proc_contrstats_ops = {
+ .owner = THIS_MODULE,
.open = seq_contrstats_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -219,6 +221,7 @@ seq_applstats_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_applications_ops = {
+ .owner = THIS_MODULE,
.open = seq_applications_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -226,21 +229,13 @@ static const struct file_operations proc_applications_ops = {
};
static const struct file_operations proc_applstats_ops = {
+ .owner = THIS_MODULE,
.open = seq_applstats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
-static void
-create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
-{
- struct proc_dir_entry *entry;
- entry = create_proc_entry(name, mode, NULL);
- if (entry)
- entry->proc_fops = f;
-}
-
// ---------------------------------------------------------------------------
static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
@@ -283,6 +278,7 @@ seq_capi_driver_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_driver_ops = {
+ .owner = THIS_MODULE,
.open = seq_capi_driver_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -296,11 +292,11 @@ kcapi_proc_init(void)
{
proc_mkdir("capi", NULL);
proc_mkdir("capi/controllers", NULL);
- create_seq_entry("capi/controller", 0, &proc_controller_ops);
- create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops);
- create_seq_entry("capi/applications", 0, &proc_applications_ops);
- create_seq_entry("capi/applstats", 0, &proc_applstats_ops);
- create_seq_entry("capi/driver", 0, &proc_driver_ops);
+ proc_create("capi/controller", 0, NULL, &proc_controller_ops);
+ proc_create("capi/contrstats", 0, NULL, &proc_contrstats_ops);
+ proc_create("capi/applications", 0, NULL, &proc_applications_ops);
+ proc_create("capi/applstats", 0, NULL, &proc_applstats_ops);
+ proc_create("capi/driver", 0, NULL, &proc_driver_ops);
}
void __exit
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 4fd4c46892e3..8b256a617c8a 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -288,13 +288,12 @@ divert_dev_init(void)
isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
if (!isdn_proc_entry)
return (-1);
- isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
+ isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO,
+ isdn_proc_entry, &isdn_fops);
if (!isdn_divert_entry) {
remove_proc_entry("isdn", init_net.proc_net);
return (-1);
}
- isdn_divert_entry->proc_fops = &isdn_fops;
- isdn_divert_entry->owner = THIS_MODULE;
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index fceeb1d57682..45d1ee93cd39 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -68,10 +68,10 @@ 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;
+ int sent = -EOPNOTSUPP;
if (!tty || !tty->driver || !skb)
- return -EFAULT;
+ return -EINVAL;
if (!skb->len) {
dev_kfree_skb_any(skb);
@@ -80,7 +80,8 @@ static int write_modem(struct cardstate *cs)
}
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, skb->data, skb->len);
+ if (tty->ops->write)
+ sent = tty->ops->write(tty, skb->data, skb->len);
gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);
if (sent < 0) {
/* error */
@@ -120,7 +121,7 @@ static int send_cb(struct cardstate *cs)
if (cb->len) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len);
+ sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len);
if (sent < 0) {
/* error */
gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);
@@ -440,14 +441,14 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsi
struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear;
- if (!tty || !tty->driver || !tty->driver->tiocmset)
- return -EFAULT;
+ if (!tty || !tty->driver || !tty->ops->tiocmset)
+ return -EINVAL;
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);
+ return tty->ops->tiocmset(tty, NULL, set, clear);
}
static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
index 0632a2606998..fae895828a17 100644
--- a/drivers/isdn/hardware/eicon/divasproc.c
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -125,15 +125,11 @@ static const struct file_operations divas_fops = {
int create_divas_proc(void)
{
- divas_proc_entry = create_proc_entry(divas_proc_name,
- S_IFREG | S_IRUGO,
- proc_net_eicon);
+ proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon,
+ &divas_fops);
if (!divas_proc_entry)
return (0);
- divas_proc_entry->proc_fops = &divas_fops;
- divas_proc_entry->owner = THIS_MODULE;
-
return (1);
}
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 27d890b48f88..15906d005b05 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -370,6 +370,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
/******************************************************/
static const struct file_operations conf_fops =
{
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.read = hysdn_conf_read,
.write = hysdn_conf_write,
@@ -402,11 +403,10 @@ hysdn_procconf_init(void)
while (card) {
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
- if ((card->procconf = (void *) create_proc_entry(conf_name,
- S_IFREG | S_IRUGO | S_IWUSR,
- hysdn_proc_entry)) != NULL) {
- ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
- ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE;
+ if ((card->procconf = (void *) proc_create(conf_name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ hysdn_proc_entry,
+ &conf_fops)) != NULL) {
hysdn_proclog_init(card); /* init the log file entry */
}
card = card->next; /* next entry */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 27b3991fb0ec..8991d2c8ee4a 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -380,6 +380,7 @@ hysdn_log_poll(struct file *file, poll_table * wait)
/**************************************************/
static const struct file_operations log_fops =
{
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.read = hysdn_log_read,
.write = hysdn_log_write,
@@ -402,10 +403,9 @@ hysdn_proclog_init(hysdn_card * card)
if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
- if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
- pd->log->proc_fops = &log_fops;
- pd->log->owner = THIS_MODULE;
- }
+ pd->log = proc_create(pd->log_name,
+ S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry,
+ &log_fops);
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 8af0df1d5b8c..1a2222cbb805 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1352,12 +1352,14 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
+ lock_kernel();
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
#endif
control = info->mcr;
status = info->msr;
+ unlock_kernel();
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
@@ -1381,6 +1383,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
#endif
+ lock_kernel();
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR) {
@@ -1402,6 +1405,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
isdn_tty_modem_hup(info, 1);
}
}
+ unlock_kernel();
return 0;
}
@@ -1435,21 +1439,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
return retval;
tty_wait_until_sent(tty, 0);
return 0;
- case TIOCGSOFTCAR:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
-#endif
- return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
- case TIOCSSOFTCAR:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
-#endif
- if (get_user(arg, (ulong __user *) arg))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
@@ -1472,13 +1461,14 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!old_termios)
isdn_tty_change_speed(info);
else {
- if (tty->termios->c_cflag == old_termios->c_cflag)
+ if (tty->termios->c_cflag == old_termios->c_cflag &&
+ tty->termios->c_ispeed == old_termios->c_ispeed &&
+ tty->termios->c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios->c_cflag & CRTSCTS))
tty->hw_stopped = 0;
- }
}
}
@@ -1718,9 +1708,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
}
dev->modempoll--;
isdn_tty_shutdown(info);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ isdn_tty_flush_buffer(tty);
tty_ldisc_flush(tty);
info->tty = NULL;
info->ncarrier = 0;
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index ac05a928f764..b3c54be74556 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -105,7 +105,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
led_cdev->dev = device_create(leds_class, parent, 0, "%s",
led_cdev->name);
- if (unlikely(IS_ERR(led_cdev->dev)))
+ if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
dev_set_drvdata(led_cdev->dev, led_cdev);
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 2bc9bf7e88e5..8080249957af 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -85,27 +85,34 @@ static unsigned desc_size(const struct lguest_device_desc *desc)
+ desc->config_len;
}
-/* This tests (and acknowleges) a feature bit. */
-static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
+/* This gets the device's feature bits. */
+static u32 lg_get_features(struct virtio_device *vdev)
{
+ unsigned int i;
+ u32 features = 0;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
- u8 *features;
-
- /* Obviously if they ask for a feature off the end of our feature
- * bitmap, it's not set. */
- if (fbit / 8 > desc->feature_len)
- return false;
-
- /* The feature bitmap comes after the virtqueues. */
- features = lg_features(desc);
- if (!(features[fbit / 8] & (1 << (fbit % 8))))
- return false;
-
- /* We set the matching bit in the other half of the bitmap to tell the
- * Host we want to use this feature. We don't use this yet, but we
- * could in future. */
- features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
- return true;
+ u8 *in_features = lg_features(desc);
+
+ /* We do this the slow but generic way. */
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+ if (in_features[i / 8] & (1 << (i % 8)))
+ features |= (1 << i);
+
+ return features;
+}
+
+static void lg_set_features(struct virtio_device *vdev, u32 features)
+{
+ unsigned int i;
+ struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+ /* Second half of bitmap is features we accept. */
+ u8 *out_features = lg_features(desc) + desc->feature_len;
+
+ memset(out_features, 0, desc->feature_len);
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
+ if (features & (1 << i))
+ out_features[i / 8] |= (1 << (i % 8));
+ }
}
/* Once they've found a field, getting a copy of it is easy. */
@@ -137,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev)
return to_lgdev(vdev)->desc->status;
}
+/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
+ * descriptor address of the device. A zero status means "reset". */
+static void set_status(struct virtio_device *vdev, u8 status)
+{
+ unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
+
+ /* We set the status. */
+ to_lgdev(vdev)->desc->status = status;
+ hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+}
+
static void lg_set_status(struct virtio_device *vdev, u8 status)
{
BUG_ON(!status);
- to_lgdev(vdev)->desc->status = status;
+ set_status(vdev, status);
}
-/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
- * address of the device. The Host will zero the status and all the
- * features. */
static void lg_reset(struct virtio_device *vdev)
{
- unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
-
- hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+ set_status(vdev, 0);
}
/*
@@ -286,7 +299,8 @@ static void lg_del_vq(struct virtqueue *vq)
/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
- .feature = lg_feature,
+ .get_features = lg_get_features,
+ .set_features = lg_set_features,
.get = lg_get,
.set = lg_set,
.get_status = lg_get_status,
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 645e6e040bfb..e73a000473cc 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -102,7 +102,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
{
/* We have a limited number the number of CPUs in the lguest struct. */
- if (id >= NR_CPUS)
+ if (id >= ARRAY_SIZE(cpu->lg->cpus))
return -EINVAL;
/* Set up this CPU's id, and pointer back to the lguest struct. */
@@ -251,8 +251,6 @@ static ssize_t write(struct file *file, const char __user *in,
if (!lg || (cpu_id >= lg->nr_cpus))
return -EINVAL;
cpu = &lg->cpus[cpu_id];
- if (!cpu)
- return -EINVAL;
/* Once the Guest is dead, you can only read() why it died. */
if (lg->dead)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 77f50b63a970..b52659620d50 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -234,6 +234,14 @@ config WINDFARM_PM112
which are the recent dual and quad G5 machines using the
970MP dual-core processor.
+config WINDFARM_PM121
+ tristate "Support for thermal management on PowerMac12,1"
+ depends on WINDFARM && I2C && PMAC_SMU
+ select I2C_POWERMAC
+ help
+ This driver provides thermal control for the PowerMac12,1
+ which is the iMac G5 (iSight).
+
config ANSLCD
tristate "Support for ANS LCD display"
depends on ADB_CUDA && PPC_PMAC
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 2dfc3f4eaf42..e3132efa17c0 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \
windfarm_smu_sensors.o \
windfarm_max6690_sensor.o \
windfarm_lm75_sensor.o windfarm_pid.o
+obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \
+ windfarm_smu_controls.o \
+ windfarm_smu_sensors.o \
+ windfarm_max6690_sensor.o \
+ windfarm_lm75_sensor.o windfarm_pid.o
obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 20978205cd02..dbaad39020a1 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -37,7 +37,7 @@
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/platform_device.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#ifdef CONFIG_PPC
@@ -102,7 +102,7 @@ static struct adb_handler {
} adb_handler[16];
/*
- * The adb_handler_sem mutex protects all accesses to the original_address
+ * The adb_handler_mutex mutex protects all accesses to the original_address
* and handler_id fields of adb_handler[i] for all i, and changes to the
* handler field.
* Accesses to the handler field are protected by the adb_handler_lock
@@ -110,7 +110,7 @@ static struct adb_handler {
* time adb_unregister returns, we know that the old handler isn't being
* called.
*/
-static DECLARE_MUTEX(adb_handler_sem);
+static DEFINE_MUTEX(adb_handler_mutex);
static DEFINE_RWLOCK(adb_handler_lock);
#if 0
@@ -334,7 +334,7 @@ int __init adb_init(void)
return 0;
}
-__initcall(adb_init);
+device_initcall(adb_init);
static int
do_adb_reset_bus(void)
@@ -355,7 +355,7 @@ do_adb_reset_bus(void)
msleep(500);
}
- down(&adb_handler_sem);
+ mutex_lock(&adb_handler_mutex);
write_lock_irq(&adb_handler_lock);
memset(adb_handler, 0, sizeof(adb_handler));
write_unlock_irq(&adb_handler_lock);
@@ -376,7 +376,7 @@ do_adb_reset_bus(void)
if (adb_controller->autopoll)
adb_controller->autopoll(autopoll_devs);
}
- up(&adb_handler_sem);
+ mutex_unlock(&adb_handler_mutex);
blocking_notifier_call_chain(&adb_client_list,
ADB_MSG_POST_RESET, NULL);
@@ -454,7 +454,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids,
{
int i;
- down(&adb_handler_sem);
+ mutex_lock(&adb_handler_mutex);
ids->nids = 0;
for (i = 1; i < 16; i++) {
if ((adb_handler[i].original_address == default_id) &&
@@ -472,7 +472,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids,
ids->id[ids->nids++] = i;
}
}
- up(&adb_handler_sem);
+ mutex_unlock(&adb_handler_mutex);
return ids->nids;
}
@@ -481,7 +481,7 @@ adb_unregister(int index)
{
int ret = -ENODEV;
- down(&adb_handler_sem);
+ mutex_lock(&adb_handler_mutex);
write_lock_irq(&adb_handler_lock);
if (adb_handler[index].handler) {
while(adb_handler[index].busy) {
@@ -493,7 +493,7 @@ adb_unregister(int index)
adb_handler[index].handler = NULL;
}
write_unlock_irq(&adb_handler_lock);
- up(&adb_handler_sem);
+ mutex_unlock(&adb_handler_mutex);
return ret;
}
@@ -557,19 +557,19 @@ adb_try_handler_change(int address, int new_id)
{
int ret;
- down(&adb_handler_sem);
+ mutex_lock(&adb_handler_mutex);
ret = try_handler_change(address, new_id);
- up(&adb_handler_sem);
+ mutex_unlock(&adb_handler_mutex);
return ret;
}
int
adb_get_infos(int address, int *original_address, int *handler_id)
{
- down(&adb_handler_sem);
+ mutex_lock(&adb_handler_mutex);
*original_address = adb_handler[address].original_address;
*handler_id = adb_handler[address].handler_id;
- up(&adb_handler_sem);
+ mutex_unlock(&adb_handler_mutex);
return (*original_address != 0);
}
@@ -628,10 +628,10 @@ do_adb_query(struct adb_request *req)
case ADB_QUERY_GETDEVINFO:
if (req->nbytes < 3)
break;
- down(&adb_handler_sem);
+ mutex_lock(&adb_handler_mutex);
req->reply[0] = adb_handler[req->data[2]].original_address;
req->reply[1] = adb_handler[req->data[2]].handler_id;
- up(&adb_handler_sem);
+ mutex_unlock(&adb_handler_mutex);
req->complete = 1;
req->reply_len = 2;
adb_write_done(req);
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 1e0a69a5e815..ddfb426a9abd 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -122,6 +122,7 @@
#include <linux/kmod.h>
#include <linux/i2c.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
@@ -169,7 +170,7 @@ static int rackmac;
static s32 dimm_output_clamp;
static int fcu_rpm_shift;
static int fcu_tickle_ticks;
-static DECLARE_MUTEX(driver_lock);
+static DEFINE_MUTEX(driver_lock);
/*
* We have 3 types of CPU PID control. One is "split" old style control
@@ -729,9 +730,9 @@ static void fetch_cpu_pumps_minmax(void)
static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
ssize_t r; \
- down(&driver_lock); \
+ mutex_lock(&driver_lock); \
r = sprintf(buf, "%d.%03d", FIX32TOPRINT(data)); \
- up(&driver_lock); \
+ mutex_unlock(&driver_lock); \
return r; \
}
#define BUILD_SHOW_FUNC_INT(name, data) \
@@ -1803,11 +1804,11 @@ static int main_control_loop(void *x)
{
DBG("main_control_loop started\n");
- down(&driver_lock);
+ mutex_lock(&driver_lock);
if (start_fcu() < 0) {
printk(KERN_ERR "kfand: failed to start FCU\n");
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
goto out;
}
@@ -1822,14 +1823,14 @@ static int main_control_loop(void *x)
fcu_tickle_ticks = FCU_TICKLE_TICKS;
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
while (state == state_attached) {
unsigned long elapsed, start;
start = jiffies;
- down(&driver_lock);
+ mutex_lock(&driver_lock);
/* Tickle the FCU just in case */
if (--fcu_tickle_ticks < 0) {
@@ -1861,7 +1862,7 @@ static int main_control_loop(void *x)
do_monitor_slots(&slots_state);
else
do_monitor_drives(&drives_state);
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
if (critical_state == 1) {
printk(KERN_WARNING "Temperature control detected a critical condition\n");
@@ -2019,13 +2020,13 @@ static void detach_fcu(void)
*/
static int therm_pm72_attach(struct i2c_adapter *adapter)
{
- down(&driver_lock);
+ mutex_lock(&driver_lock);
/* Check state */
if (state == state_detached)
state = state_attaching;
if (state != state_attaching) {
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
return 0;
}
@@ -2054,7 +2055,7 @@ static int therm_pm72_attach(struct i2c_adapter *adapter)
state = state_attached;
start_control_loops();
}
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
return 0;
}
@@ -2065,16 +2066,16 @@ static int therm_pm72_attach(struct i2c_adapter *adapter)
*/
static int therm_pm72_detach(struct i2c_adapter *adapter)
{
- down(&driver_lock);
+ mutex_lock(&driver_lock);
if (state != state_detached)
state = state_detaching;
/* Stop control loops if any */
DBG("stopping control loops\n");
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
stop_control_loops();
- down(&driver_lock);
+ mutex_lock(&driver_lock);
if (u3_0 != NULL && !strcmp(adapter->name, "u3 0")) {
DBG("lost U3-0, disposing control loops\n");
@@ -2090,7 +2091,7 @@ static int therm_pm72_detach(struct i2c_adapter *adapter)
if (u3_0 == NULL && u3_1 == NULL)
state = state_detached;
- up(&driver_lock);
+ mutex_unlock(&driver_lock);
return 0;
}
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 7e10c3ab4d50..b92b959fe16e 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
*/
if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
lm->sens.name = "hd-temp";
+ else if (!strcmp(loc, "Incoming Air Temp"))
+ lm->sens.name = "incoming-air-temp";
+ else if (!strcmp(loc, "ODD Temp"))
+ lm->sens.name = "optical-drive-temp";
+ else if (!strcmp(loc, "HD Temp"))
+ lm->sens.name = "hard-drive-temp";
else
goto fail;
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 5f03aab9fb5d..e207a90d6b27 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -77,18 +77,28 @@ static struct wf_sensor_ops wf_max6690_ops = {
.owner = THIS_MODULE,
};
-static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
+static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
+ const char *loc)
{
struct wf_6690_sensor *max;
- char *name = "backside-temp";
+ char *name;
max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
if (max == NULL) {
printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: "
- "no memory\n", name);
+ "no memory\n", loc);
return;
}
+ if (!strcmp(loc, "BACKSIDE"))
+ name = "backside-temp";
+ else if (!strcmp(loc, "NB Ambient"))
+ name = "north-bridge-temp";
+ else if (!strcmp(loc, "GPU Ambient"))
+ name = "gpu-temp";
+ else
+ goto fail;
+
max->sens.ops = &wf_max6690_ops;
max->sens.name = name;
max->i2c.addr = addr >> 1;
@@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
if (loc == NULL || addr == 0)
continue;
printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
- if (strcmp(loc, "BACKSIDE"))
- continue;
- wf_max6690_create(adapter, addr);
+ wf_max6690_create(adapter, addr, loc);
}
return 0;
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
new file mode 100644
index 000000000000..66ec4fb115bb
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -0,0 +1,1040 @@
+/*
+ * Windfarm PowerMac thermal control. iMac G5 iSight
+ *
+ * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com>
+ *
+ * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
+ * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ *
+ *
+ * PowerMac12,1
+ * ============
+ *
+ *
+ * The algorithm used is the PID control algorithm, used the same way
+ * the published Darwin code does, using the same values that are
+ * present in the Darwin 8.10 snapshot property lists (note however
+ * that none of the code has been re-used, it's a complete
+ * re-implementation
+ *
+ * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight
+ * 17" while Model 3 is iMac G5 20". They do have both the same
+ * controls with a tiny difference. The control-ids of hard-drive-fan
+ * and cpu-fan is swapped.
+ *
+ *
+ * Target Correction :
+ *
+ * controls have a target correction calculated as :
+ *
+ * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value
+ * new_value = max(new_value, max(new_min, 0))
+ *
+ * OD Fan control correction.
+ *
+ * # model_id: 2
+ * offset : -19563152
+ * slope : 1956315
+ *
+ * # model_id: 3
+ * offset : -15650652
+ * slope : 1565065
+ *
+ * HD Fan control correction.
+ *
+ * # model_id: 2
+ * offset : -15650652
+ * slope : 1565065
+ *
+ * # model_id: 3
+ * offset : -19563152
+ * slope : 1956315
+ *
+ * CPU Fan control correction.
+ *
+ * # model_id: 2
+ * offset : -25431900
+ * slope : 2543190
+ *
+ * # model_id: 3
+ * offset : -15650652
+ * slope : 1565065
+ *
+ *
+ * Target rubber-banding :
+ *
+ * Some controls have a target correction which depends on another
+ * control value. The correction is computed in the following way :
+ *
+ * new_min = ref_value * slope + offset
+ *
+ * ref_value is the value of the reference control. If new_min is
+ * greater than 0, then we correct the target value using :
+ *
+ * new_target = max (new_target, new_min >> 16)
+ *
+ *
+ * # model_id : 2
+ * control : cpu-fan
+ * ref : optical-drive-fan
+ * offset : -15650652
+ * slope : 1565065
+ *
+ * # model_id : 3
+ * control : optical-drive-fan
+ * ref : hard-drive-fan
+ * offset : -32768000
+ * slope : 65536
+ *
+ *
+ * In order to have the moste efficient correction with those
+ * dependencies, we must trigger HD loop before OD loop before CPU
+ * loop.
+ *
+ *
+ * The various control loops found in Darwin config file are:
+ *
+ * HD Fan control loop.
+ *
+ * # model_id: 2
+ * control : hard-drive-fan
+ * sensor : hard-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x002D70A3
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x370000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : hard-drive-fan
+ * sensor : hard-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x002170A3
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x370000
+ * Interval = 5s
+ *
+ * OD Fan control loop.
+ *
+ * # model_id: 2
+ * control : optical-drive-fan
+ * sensor : optical-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x001FAE14
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x320000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : optical-drive-fan
+ * sensor : optical-drive-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x001FAE14
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x320000
+ * Interval = 5s
+ *
+ * GPU Fan control loop.
+ *
+ * # model_id: 2
+ * control : hard-drive-fan
+ * sensor : gpu-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x002A6666
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x5A0000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : cpu-fan
+ * sensor : gpu-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x0010CCCC
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x500000
+ * Interval = 5s
+ *
+ * KODIAK (aka northbridge) Fan control loop.
+ *
+ * # model_id: 2
+ * control : optical-drive-fan
+ * sensor : north-bridge-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x003BD70A
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x550000
+ * Interval = 5s
+ *
+ * # model_id: 3
+ * control : hard-drive-fan
+ * sensor : north-bridge-temp
+ * PID params : G_d = 0x00000000
+ * G_p = 0x0030F5C2
+ * G_r = 0x00019999
+ * History = 2 entries
+ * Input target = 0x550000
+ * Interval = 5s
+ *
+ * CPU Fan control loop.
+ *
+ * control : cpu-fan
+ * sensors : cpu-temp, cpu-power
+ * PID params : from SDB partition
+ *
+ *
+ * CPU Slew control loop.
+ *
+ * control : cpufreq-clamp
+ * sensor : cpu-temp
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+
+#define VERSION "0.3"
+
+static int pm121_mach_model; /* machine model id */
+
+/* Controls & sensors */
+static struct wf_sensor *sensor_cpu_power;
+static struct wf_sensor *sensor_cpu_temp;
+static struct wf_sensor *sensor_cpu_voltage;
+static struct wf_sensor *sensor_cpu_current;
+static struct wf_sensor *sensor_gpu_temp;
+static struct wf_sensor *sensor_north_bridge_temp;
+static struct wf_sensor *sensor_hard_drive_temp;
+static struct wf_sensor *sensor_optical_drive_temp;
+static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */
+
+enum {
+ FAN_CPU,
+ FAN_HD,
+ FAN_OD,
+ CPUFREQ,
+ N_CONTROLS
+};
+static struct wf_control *controls[N_CONTROLS] = {};
+
+/* Set to kick the control loop into life */
+static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started;
+
+enum {
+ FAILURE_FAN = 1 << 0,
+ FAILURE_SENSOR = 1 << 1,
+ FAILURE_OVERTEMP = 1 << 2
+};
+
+/* All sys loops. Note the HD before the OD loop in order to have it
+ run before. */
+enum {
+ LOOP_GPU, /* control = hd or cpu, but luckily,
+ it doesn't matter */
+ LOOP_HD, /* control = hd */
+ LOOP_KODIAK, /* control = hd or od */
+ LOOP_OD, /* control = od */
+ N_LOOPS
+};
+
+static const char *loop_names[N_LOOPS] = {
+ "GPU",
+ "HD",
+ "KODIAK",
+ "OD",
+};
+
+#define PM121_NUM_CONFIGS 2
+
+static unsigned int pm121_failure_state;
+static int pm121_readjust, pm121_skipping;
+static s32 average_power;
+
+struct pm121_correction {
+ int offset;
+ int slope;
+};
+
+static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
+ /* FAN_OD */
+ {
+ /* MODEL 2 */
+ { .offset = -19563152,
+ .slope = 1956315
+ },
+ /* MODEL 3 */
+ { .offset = -15650652,
+ .slope = 1565065
+ },
+ },
+ /* FAN_HD */
+ {
+ /* MODEL 2 */
+ { .offset = -15650652,
+ .slope = 1565065
+ },
+ /* MODEL 3 */
+ { .offset = -19563152,
+ .slope = 1956315
+ },
+ },
+ /* FAN_CPU */
+ {
+ /* MODEL 2 */
+ { .offset = -25431900,
+ .slope = 2543190
+ },
+ /* MODEL 3 */
+ { .offset = -15650652,
+ .slope = 1565065
+ },
+ },
+ /* CPUFREQ has no correction (and is not implemented at all) */
+};
+
+struct pm121_connection {
+ unsigned int control_id;
+ unsigned int ref_id;
+ struct pm121_correction correction;
+};
+
+static struct pm121_connection pm121_connections[] = {
+ /* MODEL 2 */
+ { .control_id = FAN_CPU,
+ .ref_id = FAN_OD,
+ { .offset = -32768000,
+ .slope = 65536
+ }
+ },
+ /* MODEL 3 */
+ { .control_id = FAN_OD,
+ .ref_id = FAN_HD,
+ { .offset = -32768000,
+ .slope = 65536
+ }
+ },
+};
+
+/* pointer to the current model connection */
+static struct pm121_connection *pm121_connection;
+
+/*
+ * ****** System Fans Control Loop ******
+ *
+ */
+
+/* Since each loop handles only one control and we want to avoid
+ * writing virtual control, we store the control correction with the
+ * loop params. Some data are not set, there are common to all loop
+ * and thus, hardcoded.
+ */
+struct pm121_sys_param {
+ /* purely informative since we use mach_model-2 as index */
+ int model_id;
+ struct wf_sensor **sensor; /* use sensor_id instead ? */
+ s32 gp, itarget;
+ unsigned int control_id;
+};
+
+static struct pm121_sys_param
+pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
+ /* GPU Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_gpu_temp,
+ .gp = 0x002A6666,
+ .itarget = 0x5A0000,
+ .control_id = FAN_HD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_gpu_temp,
+ .gp = 0x0010CCCC,
+ .itarget = 0x500000,
+ .control_id = FAN_CPU,
+ },
+ },
+ /* HD Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_hard_drive_temp,
+ .gp = 0x002D70A3,
+ .itarget = 0x370000,
+ .control_id = FAN_HD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_hard_drive_temp,
+ .gp = 0x002170A3,
+ .itarget = 0x370000,
+ .control_id = FAN_HD,
+ },
+ },
+ /* KODIAK Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_north_bridge_temp,
+ .gp = 0x003BD70A,
+ .itarget = 0x550000,
+ .control_id = FAN_OD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_north_bridge_temp,
+ .gp = 0x0030F5C2,
+ .itarget = 0x550000,
+ .control_id = FAN_HD,
+ },
+ },
+ /* OD Fan control loop */
+ {
+ { .model_id = 2,
+ .sensor = &sensor_optical_drive_temp,
+ .gp = 0x001FAE14,
+ .itarget = 0x320000,
+ .control_id = FAN_OD,
+ },
+ { .model_id = 3,
+ .sensor = &sensor_optical_drive_temp,
+ .gp = 0x001FAE14,
+ .itarget = 0x320000,
+ .control_id = FAN_OD,
+ },
+ },
+};
+
+/* the hardcoded values */
+#define PM121_SYS_GD 0x00000000
+#define PM121_SYS_GR 0x00019999
+#define PM121_SYS_HISTORY_SIZE 2
+#define PM121_SYS_INTERVAL 5
+
+/* State data used by the system fans control loop
+ */
+struct pm121_sys_state {
+ int ticks;
+ s32 setpoint;
+ struct wf_pid_state pid;
+};
+
+struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
+
+/*
+ * ****** CPU Fans Control Loop ******
+ *
+ */
+
+#define PM121_CPU_INTERVAL 1
+
+/* State data used by the cpu fans control loop
+ */
+struct pm121_cpu_state {
+ int ticks;
+ s32 setpoint;
+ struct wf_cpu_pid_state pid;
+};
+
+static struct pm121_cpu_state *pm121_cpu_state;
+
+
+
+/*
+ * ***** Implementation *****
+ *
+ */
+
+/* correction the value using the output-low-bound correction algo */
+static s32 pm121_correct(s32 new_setpoint,
+ unsigned int control_id,
+ s32 min)
+{
+ s32 new_min;
+ struct pm121_correction *correction;
+ correction = &corrections[control_id][pm121_mach_model - 2];
+
+ new_min = (average_power * correction->slope) >> 16;
+ new_min += correction->offset;
+ new_min = (new_min >> 16) + min;
+
+ return max(new_setpoint, max(new_min, 0));
+}
+
+static s32 pm121_connect(unsigned int control_id, s32 setpoint)
+{
+ s32 new_min, value, new_setpoint;
+
+ if (pm121_connection->control_id == control_id) {
+ controls[control_id]->ops->get_value(controls[control_id],
+ &value);
+ new_min = value * pm121_connection->correction.slope;
+ new_min += pm121_connection->correction.offset;
+ if (new_min > 0) {
+ new_setpoint = max(setpoint, (new_min >> 16));
+ if (new_setpoint != setpoint) {
+ pr_debug("pm121: %s depending on %s, "
+ "corrected from %d to %d RPM\n",
+ controls[control_id]->name,
+ controls[pm121_connection->ref_id]->name,
+ (int) setpoint, (int) new_setpoint);
+ }
+ } else
+ new_setpoint = setpoint;
+ }
+ /* no connection */
+ else
+ new_setpoint = setpoint;
+
+ return new_setpoint;
+}
+
+/* FAN LOOPS */
+static void pm121_create_sys_fans(int loop_id)
+{
+ struct pm121_sys_param *param = NULL;
+ struct wf_pid_param pid_param;
+ struct wf_control *control = NULL;
+ int i;
+
+ /* First, locate the params for this model */
+ for (i = 0; i < PM121_NUM_CONFIGS; i++) {
+ if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) {
+ param = &(pm121_sys_all_params[loop_id][i]);
+ break;
+ }
+ }
+
+ /* No params found, put fans to max */
+ if (param == NULL) {
+ printk(KERN_WARNING "pm121: %s fan config not found "
+ " for this machine model\n",
+ loop_names[loop_id]);
+ goto fail;
+ }
+
+ control = controls[param->control_id];
+
+ /* Alloc & initialize state */
+ pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
+ GFP_KERNEL);
+ if (pm121_sys_state[loop_id] == NULL) {
+ printk(KERN_WARNING "pm121: Memory allocation error\n");
+ goto fail;
+ }
+ pm121_sys_state[loop_id]->ticks = 1;
+
+ /* Fill PID params */
+ pid_param.gd = PM121_SYS_GD;
+ pid_param.gp = param->gp;
+ pid_param.gr = PM121_SYS_GR;
+ pid_param.interval = PM121_SYS_INTERVAL;
+ pid_param.history_len = PM121_SYS_HISTORY_SIZE;
+ pid_param.itarget = param->itarget;
+ pid_param.min = control->ops->get_min(control);
+ pid_param.max = control->ops->get_max(control);
+
+ wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
+
+ pr_debug("pm121: %s Fan control loop initialized.\n"
+ " itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
+ loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
+ pid_param.min, pid_param.max);
+ return;
+
+ fail:
+ /* note that this is not optimal since another loop may still
+ control the same control */
+ printk(KERN_WARNING "pm121: failed to set up %s loop "
+ "setting \"%s\" to max speed.\n",
+ loop_names[loop_id], control->name);
+
+ if (control)
+ wf_control_set_max(control);
+}
+
+static void pm121_sys_fans_tick(int loop_id)
+{
+ struct pm121_sys_param *param;
+ struct pm121_sys_state *st;
+ struct wf_sensor *sensor;
+ struct wf_control *control;
+ s32 temp, new_setpoint;
+ int rc;
+
+ param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
+ st = pm121_sys_state[loop_id];
+ sensor = *(param->sensor);
+ control = controls[param->control_id];
+
+ if (--st->ticks != 0) {
+ if (pm121_readjust)
+ goto readjust;
+ return;
+ }
+ st->ticks = PM121_SYS_INTERVAL;
+
+ rc = sensor->ops->get_value(sensor, &temp);
+ if (rc) {
+ printk(KERN_WARNING "windfarm: %s sensor error %d\n",
+ sensor->name, rc);
+ pm121_failure_state |= FAILURE_SENSOR;
+ return;
+ }
+
+ pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n",
+ loop_names[loop_id], sensor->name,
+ FIX32TOPRINT(temp));
+
+ new_setpoint = wf_pid_run(&st->pid, temp);
+
+ /* correction */
+ new_setpoint = pm121_correct(new_setpoint,
+ param->control_id,
+ st->pid.param.min);
+ /* linked corretion */
+ new_setpoint = pm121_connect(param->control_id, new_setpoint);
+
+ if (new_setpoint == st->setpoint)
+ return;
+ st->setpoint = new_setpoint;
+ pr_debug("pm121: %s corrected setpoint: %d RPM\n",
+ control->name, (int)new_setpoint);
+ readjust:
+ if (control && pm121_failure_state == 0) {
+ rc = control->ops->set_value(control, st->setpoint);
+ if (rc) {
+ printk(KERN_WARNING "windfarm: %s fan error %d\n",
+ control->name, rc);
+ pm121_failure_state |= FAILURE_FAN;
+ }
+ }
+}
+
+
+/* CPU LOOP */
+static void pm121_create_cpu_fans(void)
+{
+ struct wf_cpu_pid_param pid_param;
+ const struct smu_sdbp_header *hdr;
+ struct smu_sdbp_cpupiddata *piddata;
+ struct smu_sdbp_fvt *fvt;
+ struct wf_control *fan_cpu;
+ s32 tmax, tdelta, maxpow, powadj;
+
+ fan_cpu = controls[FAN_CPU];
+
+ /* First, locate the PID params in SMU SBD */
+ hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
+ if (hdr == 0) {
+ printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
+ goto fail;
+ }
+ piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
+
+ /* Get the FVT params for operating point 0 (the only supported one
+ * for now) in order to get tmax
+ */
+ hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+ if (hdr) {
+ fvt = (struct smu_sdbp_fvt *)&hdr[1];
+ tmax = ((s32)fvt->maxtemp) << 16;
+ } else
+ tmax = 0x5e0000; /* 94 degree default */
+
+ /* Alloc & initialize state */
+ pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
+ GFP_KERNEL);
+ if (pm121_cpu_state == NULL)
+ goto fail;
+ pm121_cpu_state->ticks = 1;
+
+ /* Fill PID params */
+ pid_param.interval = PM121_CPU_INTERVAL;
+ pid_param.history_len = piddata->history_len;
+ if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
+ printk(KERN_WARNING "pm121: History size overflow on "
+ "CPU control loop (%d)\n", piddata->history_len);
+ pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
+ }
+ pid_param.gd = piddata->gd;
+ pid_param.gp = piddata->gp;
+ pid_param.gr = piddata->gr / pid_param.history_len;
+
+ tdelta = ((s32)piddata->target_temp_delta) << 16;
+ maxpow = ((s32)piddata->max_power) << 16;
+ powadj = ((s32)piddata->power_adj) << 16;
+
+ pid_param.tmax = tmax;
+ pid_param.ttarget = tmax - tdelta;
+ pid_param.pmaxadj = maxpow - powadj;
+
+ pid_param.min = fan_cpu->ops->get_min(fan_cpu);
+ pid_param.max = fan_cpu->ops->get_max(fan_cpu);
+
+ wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
+
+ pr_debug("pm121: CPU Fan control initialized.\n");
+ pr_debug(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
+ FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
+ pid_param.min, pid_param.max);
+
+ return;
+
+ fail:
+ printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
+
+ if (controls[CPUFREQ])
+ wf_control_set_max(controls[CPUFREQ]);
+ if (fan_cpu)
+ wf_control_set_max(fan_cpu);
+}
+
+
+static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
+{
+ s32 new_setpoint, temp, power;
+ struct wf_control *fan_cpu = NULL;
+ int rc;
+
+ if (--st->ticks != 0) {
+ if (pm121_readjust)
+ goto readjust;
+ return;
+ }
+ st->ticks = PM121_CPU_INTERVAL;
+
+ fan_cpu = controls[FAN_CPU];
+
+ rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+ if (rc) {
+ printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
+ rc);
+ pm121_failure_state |= FAILURE_SENSOR;
+ return;
+ }
+
+ rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+ if (rc) {
+ printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
+ rc);
+ pm121_failure_state |= FAILURE_SENSOR;
+ return;
+ }
+
+ pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
+ FIX32TOPRINT(temp), FIX32TOPRINT(power));
+
+ if (temp > st->pid.param.tmax)
+ pm121_failure_state |= FAILURE_OVERTEMP;
+
+ new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
+
+ /* correction */
+ new_setpoint = pm121_correct(new_setpoint,
+ FAN_CPU,
+ st->pid.param.min);
+
+ /* connected correction */
+ new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
+
+ if (st->setpoint == new_setpoint)
+ return;
+ st->setpoint = new_setpoint;
+ pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
+
+ readjust:
+ if (fan_cpu && pm121_failure_state == 0) {
+ rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
+ if (rc) {
+ printk(KERN_WARNING "pm121: %s fan error %d\n",
+ fan_cpu->name, rc);
+ pm121_failure_state |= FAILURE_FAN;
+ }
+ }
+}
+
+/*
+ * ****** Common ******
+ *
+ */
+
+static void pm121_tick(void)
+{
+ unsigned int last_failure = pm121_failure_state;
+ unsigned int new_failure;
+ s32 total_power;
+ int i;
+
+ if (!pm121_started) {
+ pr_debug("pm121: creating control loops !\n");
+ for (i = 0; i < N_LOOPS; i++)
+ pm121_create_sys_fans(i);
+
+ pm121_create_cpu_fans();
+ pm121_started = 1;
+ }
+
+ /* skipping ticks */
+ if (pm121_skipping && --pm121_skipping)
+ return;
+
+ /* compute average power */
+ total_power = 0;
+ for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
+ total_power += pm121_cpu_state->pid.powers[i];
+
+ average_power = total_power / pm121_cpu_state->pid.param.history_len;
+
+
+ pm121_failure_state = 0;
+ for (i = 0 ; i < N_LOOPS; i++) {
+ if (pm121_sys_state[i])
+ pm121_sys_fans_tick(i);
+ }
+
+ if (pm121_cpu_state)
+ pm121_cpu_fans_tick(pm121_cpu_state);
+
+ pm121_readjust = 0;
+ new_failure = pm121_failure_state & ~last_failure;
+
+ /* If entering failure mode, clamp cpufreq and ramp all
+ * fans to full speed.
+ */
+ if (pm121_failure_state && !last_failure) {
+ for (i = 0; i < N_CONTROLS; i++) {
+ if (controls[i])
+ wf_control_set_max(controls[i]);
+ }
+ }
+
+ /* If leaving failure mode, unclamp cpufreq and readjust
+ * all fans on next iteration
+ */
+ if (!pm121_failure_state && last_failure) {
+ if (controls[CPUFREQ])
+ wf_control_set_min(controls[CPUFREQ]);
+ pm121_readjust = 1;
+ }
+
+ /* Overtemp condition detected, notify and start skipping a couple
+ * ticks to let the temperature go down
+ */
+ if (new_failure & FAILURE_OVERTEMP) {
+ wf_set_overtemp();
+ pm121_skipping = 2;
+ }
+
+ /* We only clear the overtemp condition if overtemp is cleared
+ * _and_ no other failure is present. Since a sensor error will
+ * clear the overtemp condition (can't measure temperature) at
+ * the control loop levels, but we don't want to keep it clear
+ * here in this case
+ */
+ if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+ wf_clear_overtemp();
+}
+
+
+static struct wf_control* pm121_register_control(struct wf_control *ct,
+ const char *match,
+ unsigned int id)
+{
+ if (controls[id] == NULL && !strcmp(ct->name, match)) {
+ if (wf_get_control(ct) == 0)
+ controls[id] = ct;
+ }
+ return controls[id];
+}
+
+static void pm121_new_control(struct wf_control *ct)
+{
+ int all = 1;
+
+ if (pm121_all_controls_ok)
+ return;
+
+ all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all;
+ all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all;
+ all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all;
+ all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all;
+
+ if (all)
+ pm121_all_controls_ok = 1;
+}
+
+
+
+
+static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor,
+ const char *match,
+ struct wf_sensor **var)
+{
+ if (*var == NULL && !strcmp(sensor->name, match)) {
+ if (wf_get_sensor(sensor) == 0)
+ *var = sensor;
+ }
+ return *var;
+}
+
+static void pm121_new_sensor(struct wf_sensor *sr)
+{
+ int all = 1;
+
+ if (pm121_all_sensors_ok)
+ return;
+
+ all = pm121_register_sensor(sr, "cpu-temp",
+ &sensor_cpu_temp) && all;
+ all = pm121_register_sensor(sr, "cpu-current",
+ &sensor_cpu_current) && all;
+ all = pm121_register_sensor(sr, "cpu-voltage",
+ &sensor_cpu_voltage) && all;
+ all = pm121_register_sensor(sr, "cpu-power",
+ &sensor_cpu_power) && all;
+ all = pm121_register_sensor(sr, "hard-drive-temp",
+ &sensor_hard_drive_temp) && all;
+ all = pm121_register_sensor(sr, "optical-drive-temp",
+ &sensor_optical_drive_temp) && all;
+ all = pm121_register_sensor(sr, "incoming-air-temp",
+ &sensor_incoming_air_temp) && all;
+ all = pm121_register_sensor(sr, "north-bridge-temp",
+ &sensor_north_bridge_temp) && all;
+ all = pm121_register_sensor(sr, "gpu-temp",
+ &sensor_gpu_temp) && all;
+
+ if (all)
+ pm121_all_sensors_ok = 1;
+}
+
+
+
+static int pm121_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case WF_EVENT_NEW_CONTROL:
+ pr_debug("pm121: new control %s detected\n",
+ ((struct wf_control *)data)->name);
+ pm121_new_control(data);
+ break;
+ case WF_EVENT_NEW_SENSOR:
+ pr_debug("pm121: new sensor %s detected\n",
+ ((struct wf_sensor *)data)->name);
+ pm121_new_sensor(data);
+ break;
+ case WF_EVENT_TICK:
+ if (pm121_all_controls_ok && pm121_all_sensors_ok)
+ pm121_tick();
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block pm121_events = {
+ .notifier_call = pm121_notify,
+};
+
+static int pm121_init_pm(void)
+{
+ const struct smu_sdbp_header *hdr;
+
+ hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
+ if (hdr != 0) {
+ struct smu_sdbp_sensortree *st =
+ (struct smu_sdbp_sensortree *)&hdr[1];
+ pm121_mach_model = st->model_id;
+ }
+
+ pm121_connection = &pm121_connections[pm121_mach_model - 2];
+
+ printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
+ pm121_mach_model);
+
+ return 0;
+}
+
+
+static int pm121_probe(struct platform_device *ddev)
+{
+ wf_register_client(&pm121_events);
+
+ return 0;
+}
+
+static int __devexit pm121_remove(struct platform_device *ddev)
+{
+ wf_unregister_client(&pm121_events);
+ return 0;
+}
+
+static struct platform_driver pm121_driver = {
+ .probe = pm121_probe,
+ .remove = __devexit_p(pm121_remove),
+ .driver = {
+ .name = "windfarm",
+ .bus = &platform_bus_type,
+ },
+};
+
+
+static int __init pm121_init(void)
+{
+ int rc = -ENODEV;
+
+ if (machine_is_compatible("PowerMac12,1"))
+ rc = pm121_init_pm();
+
+ if (rc == 0) {
+ request_module("windfarm_smu_controls");
+ request_module("windfarm_smu_sensors");
+ request_module("windfarm_smu_sat");
+ request_module("windfarm_lm75_sensor");
+ request_module("windfarm_max6690_sensor");
+ request_module("windfarm_cpufreq_clamp");
+ platform_driver_register(&pm121_driver);
+ }
+
+ return rc;
+}
+
+static void __exit pm121_exit(void)
+{
+
+ platform_driver_unregister(&pm121_driver);
+}
+
+
+module_init(pm121_init);
+module_exit(pm121_exit);
+
+MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
+MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 58c2590f05ec..961fa0e7c2cf 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
fct->ctrl.name = "cpu-fan";
else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive"))
fct->ctrl.name = "drive-bay-fan";
+ else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */
+ fct->ctrl.name = "hard-drive-fan";
+ else if (!strcmp(l, "ODD Fan")) /* same */
+ fct->ctrl.name = "optical-drive-fan";
/* Unrecognized fan, bail out */
if (fct->ctrl.name == NULL)
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 797918d0e59c..7f2be4baaeda 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/i2c.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
#include <asm/prom.h>
#include <asm/smu.h>
#include <asm/pmac_low_i2c.h>
@@ -36,7 +36,7 @@
struct wf_sat {
int nr;
atomic_t refcnt;
- struct semaphore mutex;
+ struct mutex mutex;
unsigned long last_read; /* jiffies when cache last updated */
u8 cache[16];
struct i2c_client i2c;
@@ -163,7 +163,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
if (sat->i2c.adapter == NULL)
return -ENODEV;
- down(&sat->mutex);
+ mutex_lock(&sat->mutex);
if (time_after(jiffies, (sat->last_read + MAX_AGE))) {
err = wf_sat_read_cache(sat);
if (err)
@@ -182,7 +182,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
err = 0;
fail:
- up(&sat->mutex);
+ mutex_unlock(&sat->mutex);
return err;
}
@@ -233,7 +233,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
sat->nr = -1;
sat->node = of_node_get(dev);
atomic_set(&sat->refcnt, 0);
- init_MUTEX(&sat->mutex);
+ mutex_init(&sat->mutex);
sat->i2c.addr = (addr >> 1) & 0x7f;
sat->i2c.adapter = adapter;
sat->i2c.driver = &wf_sat_driver;
diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c
index 0c7bfa74c8ef..494f0c2001f5 100644
--- a/drivers/mca/mca-legacy.c
+++ b/drivers/mca/mca-legacy.c
@@ -282,24 +282,6 @@ void mca_set_adapter_name(int slot, char* name)
EXPORT_SYMBOL(mca_set_adapter_name);
/**
- * mca_is_adapter_used - check if claimed by driver
- * @slot: slot to check
- *
- * Returns 1 if the slot has been claimed by a driver
- */
-
-int mca_is_adapter_used(int slot)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return 0;
-
- return mca_device_claimed(mca_dev);
-}
-EXPORT_SYMBOL(mca_is_adapter_used);
-
-/**
* mca_mark_as_used - claim an MCA device
* @slot: slot to claim
* FIXME: should we make this threadsafe
diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c
index 33d5e0820cc5..81ea0d377bf4 100644
--- a/drivers/mca/mca-proc.c
+++ b/drivers/mca/mca-proc.c
@@ -183,7 +183,7 @@ void __init mca_do_proc_init(void)
struct proc_dir_entry* node = NULL;
struct mca_device *mca_dev;
- proc_mca = proc_mkdir("mca", &proc_root);
+ proc_mca = proc_mkdir("mca", NULL);
create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 6b91b9ab1d41..3ea5ad4b7805 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -110,8 +110,6 @@ static struct request *get_failover_req(struct emc_handler *h,
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
- memset(&rq->cmd, 0, BLK_MAX_CDB);
-
rq->timeout = EMC_FAILOVER_TIMEOUT;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c
index 204bf42c9449..b63a0ab37c53 100644
--- a/drivers/md/dm-mpath-hp-sw.c
+++ b/drivers/md/dm-mpath-hp-sw.c
@@ -137,7 +137,6 @@ static struct request *hp_sw_get_request(struct dm_path *path)
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
- memset(&req->cmd, 0, BLK_MAX_CDB);
req->cmd[0] = START_STOP;
req->cmd[4] = 1;
req->cmd_len = COMMAND_SIZE(req->cmd[0]);
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c
index e04eb5c697fb..95e77734880a 100644
--- a/drivers/md/dm-mpath-rdac.c
+++ b/drivers/md/dm-mpath-rdac.c
@@ -284,7 +284,6 @@ static struct request *get_rdac_req(struct rdac_handler *h,
return NULL;
}
- memset(&rq->cmd, 0, BLK_MAX_CDB);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 51be53344214..94116eaf4709 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -873,10 +873,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q)
q->max_hw_sectors = t->limits.max_hw_sectors;
q->seg_boundary_mask = t->limits.seg_boundary_mask;
q->bounce_pfn = t->limits.bounce_pfn;
+
if (t->limits.no_cluster)
- q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER);
+ queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
else
- q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER);
+ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q);
}
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 0b8511776b3e..10748240cb2f 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -250,6 +250,7 @@ static int linear_run (mddev_t *mddev)
{
linear_conf_t *conf;
+ mddev->queue->queue_lock = &mddev->queue->__queue_lock;
conf = linear_conf(mddev, mddev->raid_disks);
if (!conf)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 87620b705bee..83eb78b00137 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -276,13 +276,15 @@ static mddev_t * mddev_find(dev_t unit)
init_waitqueue_head(&new->sb_wait);
new->reshape_position = MaxSector;
new->resync_max = MaxSector;
+ new->level = LEVEL_NONE;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
kfree(new);
return NULL;
}
- set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags);
+ /* Can be unlocked because the queue is new: no concurrency */
+ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue);
blk_queue_make_request(new->queue, md_fail_request);
@@ -1368,6 +1370,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
MD_BUG();
return -EINVAL;
}
+
+ /* prevent duplicates */
+ if (find_rdev(mddev, rdev->bdev->bd_dev))
+ return -EEXIST;
+
/* make sure rdev->size exceeds mddev->size */
if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) {
if (mddev->pers) {
@@ -1651,6 +1658,8 @@ static void md_update_sb(mddev_t * mddev, int force_change)
int sync_req;
int nospares = 0;
+ if (mddev->external)
+ return;
repeat:
spin_lock_irq(&mddev->write_lock);
@@ -1819,6 +1828,10 @@ state_show(mdk_rdev_t *rdev, char *page)
len += sprintf(page+len, "%swrite_mostly",sep);
sep = ",";
}
+ if (test_bit(Blocked, &rdev->flags)) {
+ len += sprintf(page+len, "%sblocked", sep);
+ sep = ",";
+ }
if (!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags)) {
len += sprintf(page+len, "%sspare", sep);
@@ -1835,6 +1848,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
* remove - disconnects the device
* writemostly - sets write_mostly
* -writemostly - clears write_mostly
+ * blocked - sets the Blocked flag
+ * -blocked - clears the Blocked flag
*/
int err = -EINVAL;
if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
@@ -1857,6 +1872,16 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
} else if (cmd_match(buf, "-writemostly")) {
clear_bit(WriteMostly, &rdev->flags);
err = 0;
+ } else if (cmd_match(buf, "blocked")) {
+ set_bit(Blocked, &rdev->flags);
+ err = 0;
+ } else if (cmd_match(buf, "-blocked")) {
+ clear_bit(Blocked, &rdev->flags);
+ wake_up(&rdev->blocked_wait);
+ set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+ md_wakeup_thread(rdev->mddev->thread);
+
+ err = 0;
}
return err ? err : len;
}
@@ -2096,7 +2121,7 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
rv = -EBUSY;
else
rv = entry->store(rdev, page, length);
- mddev_unlock(rdev->mddev);
+ mddev_unlock(mddev);
}
return rv;
}
@@ -2185,7 +2210,9 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
goto abort_free;
}
}
+
INIT_LIST_HEAD(&rdev->same_set);
+ init_waitqueue_head(&rdev->blocked_wait);
return rdev;
@@ -2456,7 +2483,6 @@ resync_start_show(mddev_t *mddev, char *page)
static ssize_t
resync_start_store(mddev_t *mddev, const char *buf, size_t len)
{
- /* can only set chunk_size if array is not yet active */
char *e;
unsigned long long n = simple_strtoull(buf, &e, 10);
@@ -2590,15 +2616,20 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
err = do_md_stop(mddev, 1);
else {
mddev->ro = 1;
+ set_disk_ro(mddev->gendisk, 1);
err = do_md_run(mddev);
}
break;
case read_auto:
- /* stopping an active array */
if (mddev->pers) {
- err = do_md_stop(mddev, 1);
- if (err == 0)
- mddev->ro = 2; /* FIXME mark devices writable */
+ if (mddev->ro != 1)
+ err = do_md_stop(mddev, 1);
+ else
+ err = restart_array(mddev);
+ if (err == 0) {
+ mddev->ro = 2;
+ set_disk_ro(mddev->gendisk, 0);
+ }
} else {
mddev->ro = 2;
err = do_md_run(mddev);
@@ -2611,6 +2642,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
if (atomic_read(&mddev->writes_pending) == 0) {
if (mddev->in_sync == 0) {
mddev->in_sync = 1;
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
if (mddev->persistent)
set_bit(MD_CHANGE_CLEAN,
&mddev->flags);
@@ -2634,6 +2667,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
err = 0;
} else {
mddev->ro = 0;
+ set_disk_ro(mddev->gendisk, 0);
err = do_md_run(mddev);
}
break;
@@ -3711,6 +3745,30 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->reshape_position = MaxSector;
mddev->external = 0;
mddev->persistent = 0;
+ mddev->level = LEVEL_NONE;
+ mddev->clevel[0] = 0;
+ mddev->flags = 0;
+ mddev->ro = 0;
+ mddev->metadata_type[0] = 0;
+ mddev->chunk_size = 0;
+ mddev->ctime = mddev->utime = 0;
+ mddev->layout = 0;
+ mddev->max_disks = 0;
+ mddev->events = 0;
+ mddev->delta_disks = 0;
+ mddev->new_level = LEVEL_NONE;
+ mddev->new_layout = 0;
+ mddev->new_chunk = 0;
+ mddev->curr_resync = 0;
+ mddev->resync_mismatches = 0;
+ mddev->suspend_lo = mddev->suspend_hi = 0;
+ mddev->sync_speed_min = mddev->sync_speed_max = 0;
+ mddev->recovery = 0;
+ mddev->in_sync = 0;
+ mddev->changed = 0;
+ mddev->degraded = 0;
+ mddev->barriers_work = 0;
+ mddev->safemode = 0;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4918,6 +4976,9 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
if (!rdev || test_bit(Faulty, &rdev->flags))
return;
+
+ if (mddev->external)
+ set_bit(Blocked, &rdev->flags);
/*
dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
mdname(mddev),
@@ -5364,6 +5425,8 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
md_wakeup_thread(mddev->sync_thread);
}
atomic_inc(&mddev->writes_pending);
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
if (mddev->in_sync) {
spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) {
@@ -5718,7 +5781,7 @@ static int remove_and_add_spares(mddev_t *mddev)
rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
- !mddev->external &&
+ !test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
atomic_read(&rdev->nr_pending)==0) {
@@ -5788,7 +5851,7 @@ void md_check_recovery(mddev_t *mddev)
return;
if (signal_pending(current)) {
- if (mddev->pers->sync_request) {
+ if (mddev->pers->sync_request && !mddev->external) {
printk(KERN_INFO "md: %s in immediate safe mode\n",
mdname(mddev));
mddev->safemode = 2;
@@ -5800,7 +5863,7 @@ void md_check_recovery(mddev_t *mddev)
(mddev->flags && !mddev->external) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
- (mddev->safemode == 1) ||
+ (mddev->external == 0 && mddev->safemode == 1) ||
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
&& !mddev->in_sync && mddev->recovery_cp == MaxSector)
))
@@ -5809,16 +5872,20 @@ void md_check_recovery(mddev_t *mddev)
if (mddev_trylock(mddev)) {
int spares = 0;
- spin_lock_irq(&mddev->write_lock);
- if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
- !mddev->in_sync && mddev->recovery_cp == MaxSector) {
- mddev->in_sync = 1;
- if (mddev->persistent)
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (!mddev->external) {
+ spin_lock_irq(&mddev->write_lock);
+ if (mddev->safemode &&
+ !atomic_read(&mddev->writes_pending) &&
+ !mddev->in_sync &&
+ mddev->recovery_cp == MaxSector) {
+ mddev->in_sync = 1;
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
+ spin_unlock_irq(&mddev->write_lock);
}
- if (mddev->safemode == 1)
- mddev->safemode = 0;
- spin_unlock_irq(&mddev->write_lock);
if (mddev->flags)
md_update_sb(mddev, 0);
@@ -5913,6 +5980,16 @@ void md_check_recovery(mddev_t *mddev)
}
}
+void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
+{
+ sysfs_notify(&rdev->kobj, NULL, "state");
+ wait_event_timeout(rdev->blocked_wait,
+ !test_bit(Blocked, &rdev->flags),
+ msecs_to_jiffies(5000));
+ rdev_dec_pending(rdev, mddev);
+}
+EXPORT_SYMBOL(md_wait_for_blocked_rdev);
+
static int md_notify_reboot(struct notifier_block *this,
unsigned long code, void *x)
{
@@ -5947,13 +6024,9 @@ static struct notifier_block md_notifier = {
static void md_geninit(void)
{
- struct proc_dir_entry *p;
-
dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
- p = create_proc_entry("mdstat", S_IRUGO, NULL);
- if (p)
- p->proc_fops = &md_seq_fops;
+ proc_create("mdstat", S_IRUGO, NULL, &md_seq_fops);
}
static int __init md_init(void)
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 42ee1a2dc144..4f4d1f383842 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -417,6 +417,7 @@ static int multipath_run (mddev_t *mddev)
* bookkeeping area. [whatever we allocate in multipath_run(),
* should be freed in multipath_stop()]
*/
+ mddev->queue->queue_lock = &mddev->queue->__queue_lock;
conf = kzalloc(sizeof(multipath_conf_t), GFP_KERNEL);
mddev->private = conf;
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 818b48284096..914c04ddec7c 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -280,6 +280,7 @@ static int raid0_run (mddev_t *mddev)
(mddev->chunk_size>>1)-1);
blk_queue_max_sectors(mddev->queue, mddev->chunk_size >> 9);
blk_queue_segment_boundary(mddev->queue, (mddev->chunk_size>>1) - 1);
+ mddev->queue->queue_lock = &mddev->queue->__queue_lock;
conf = kmalloc(sizeof (raid0_conf_t), GFP_KERNEL);
if (!conf)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 9fd473a6dbf5..ac409b7d83f5 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -773,7 +773,6 @@ static int make_request(struct request_queue *q, struct bio * bio)
r1bio_t *r1_bio;
struct bio *read_bio;
int i, targets = 0, disks;
- mdk_rdev_t *rdev;
struct bitmap *bitmap = mddev->bitmap;
unsigned long flags;
struct bio_list bl;
@@ -781,6 +780,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
const int rw = bio_data_dir(bio);
const int do_sync = bio_sync(bio);
int do_barriers;
+ mdk_rdev_t *blocked_rdev;
/*
* Register the new request and wait if the reconstruction
@@ -862,10 +862,17 @@ static int make_request(struct request_queue *q, struct bio * bio)
first = 0;
}
#endif
+ retry_write:
+ blocked_rdev = NULL;
rcu_read_lock();
for (i = 0; i < disks; i++) {
- if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL &&
- !test_bit(Faulty, &rdev->flags)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ atomic_inc(&rdev->nr_pending);
+ blocked_rdev = rdev;
+ break;
+ }
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
if (test_bit(Faulty, &rdev->flags)) {
rdev_dec_pending(rdev, mddev);
@@ -878,6 +885,20 @@ static int make_request(struct request_queue *q, struct bio * bio)
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ /* Wait for this device to become unblocked */
+ int j;
+
+ for (j = 0; j < i; j++)
+ if (r1_bio->bios[j])
+ rdev_dec_pending(conf->mirrors[j].rdev, mddev);
+
+ allow_barrier(conf);
+ md_wait_for_blocked_rdev(blocked_rdev, mddev);
+ wait_barrier(conf);
+ goto retry_write;
+ }
+
BUG_ON(targets == 0); /* we never fail the last device */
if (targets < conf->raid_disks) {
@@ -1914,6 +1935,9 @@ static int run(mddev_t *mddev)
if (!conf->r1bio_pool)
goto out_no_mem;
+ spin_lock_init(&conf->device_lock);
+ mddev->queue->queue_lock = &conf->device_lock;
+
rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
@@ -1937,7 +1961,6 @@ static int run(mddev_t *mddev)
}
conf->raid_disks = mddev->raid_disks;
conf->mddev = mddev;
- spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
spin_lock_init(&conf->resync_lock);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1e96aa3ff513..8536ede1e712 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -790,6 +790,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
const int do_sync = bio_sync(bio);
struct bio_list bl;
unsigned long flags;
+ mdk_rdev_t *blocked_rdev;
if (unlikely(bio_barrier(bio))) {
bio_endio(bio, -EOPNOTSUPP);
@@ -879,17 +880,23 @@ static int make_request(struct request_queue *q, struct bio * bio)
/*
* WRITE:
*/
- /* first select target devices under spinlock and
+ /* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
* bios[x] to bio
*/
raid10_find_phys(conf, r10_bio);
+ retry_write:
+ blocked_rdev = NULL;
rcu_read_lock();
for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev &&
- !test_bit(Faulty, &rdev->flags)) {
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ atomic_inc(&rdev->nr_pending);
+ blocked_rdev = rdev;
+ break;
+ }
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
r10_bio->devs[i].bio = bio;
} else {
@@ -899,6 +906,22 @@ static int make_request(struct request_queue *q, struct bio * bio)
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ /* Have to wait for this device to get unblocked, then retry */
+ int j;
+ int d;
+
+ for (j = 0; j < i; j++)
+ if (r10_bio->devs[j].bio) {
+ d = r10_bio->devs[j].devnum;
+ rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+ }
+ allow_barrier(conf);
+ md_wait_for_blocked_rdev(blocked_rdev, mddev);
+ wait_barrier(conf);
+ goto retry_write;
+ }
+
atomic_set(&r10_bio->remaining, 0);
bio_list_init(&bl);
@@ -2059,6 +2082,9 @@ static int run(mddev_t *mddev)
goto out_free_conf;
}
+ spin_lock_init(&conf->device_lock);
+ mddev->queue->queue_lock = &conf->device_lock;
+
rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
@@ -2080,7 +2106,6 @@ static int run(mddev_t *mddev)
disk->head_position = 0;
}
- spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
spin_lock_init(&conf->resync_lock);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 968dacaced6d..93fde48c0f42 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2369,8 +2369,8 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
/* complete a check operation */
if (test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) {
- clear_bit(STRIPE_OP_CHECK, &sh->ops.ack);
- clear_bit(STRIPE_OP_CHECK, &sh->ops.pending);
+ clear_bit(STRIPE_OP_CHECK, &sh->ops.ack);
+ clear_bit(STRIPE_OP_CHECK, &sh->ops.pending);
if (s->failed == 0) {
if (sh->ops.zero_sum_result == 0)
/* parity is correct (on disc,
@@ -2400,16 +2400,6 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
canceled_check = 1; /* STRIPE_INSYNC is not set */
}
- /* check if we can clear a parity disk reconstruct */
- if (test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete) &&
- test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
-
- clear_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending);
- clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
- clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.ack);
- clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
- }
-
/* start a new check operation if there are no failures, the stripe is
* not insync, and a repair is not in flight
*/
@@ -2424,6 +2414,17 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
}
}
+ /* check if we can clear a parity disk reconstruct */
+ if (test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete) &&
+ test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
+
+ clear_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.ack);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
+ }
+
+
/* Wait for check parity and compute block operations to complete
* before write-back. If a failure occurred while the check operation
* was in flight we need to cycle this stripe through handle_stripe
@@ -2607,6 +2608,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
}
}
+
/*
* handle_stripe - do things to a stripe.
*
@@ -2632,6 +2634,7 @@ static void handle_stripe5(struct stripe_head *sh)
struct stripe_head_state s;
struct r5dev *dev;
unsigned long pending = 0;
+ mdk_rdev_t *blocked_rdev = NULL;
memset(&s, 0, sizeof(s));
pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d "
@@ -2691,6 +2694,11 @@ static void handle_stripe5(struct stripe_head *sh)
if (dev->written)
s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ blocked_rdev = rdev;
+ atomic_inc(&rdev->nr_pending);
+ break;
+ }
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
clear_bit(R5_ReadError, &dev->flags);
@@ -2705,6 +2713,11 @@ static void handle_stripe5(struct stripe_head *sh)
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ set_bit(STRIPE_HANDLE, &sh->state);
+ goto unlock;
+ }
+
if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending))
sh->ops.count++;
@@ -2894,8 +2907,13 @@ static void handle_stripe5(struct stripe_head *sh)
if (sh->ops.count)
pending = get_stripe_work(sh);
+ unlock:
spin_unlock(&sh->lock);
+ /* wait for this device to become unblocked */
+ if (unlikely(blocked_rdev))
+ md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+
if (pending)
raid5_run_ops(sh, pending);
@@ -2912,6 +2930,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
struct stripe_head_state s;
struct r6_state r6s;
struct r5dev *dev, *pdev, *qdev;
+ mdk_rdev_t *blocked_rdev = NULL;
r6s.qd_idx = raid6_next_disk(pd_idx, disks);
pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
@@ -2975,6 +2994,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
if (dev->written)
s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ blocked_rdev = rdev;
+ atomic_inc(&rdev->nr_pending);
+ break;
+ }
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
clear_bit(R5_ReadError, &dev->flags);
@@ -2989,6 +3013,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
set_bit(R5_Insync, &dev->flags);
}
rcu_read_unlock();
+
+ if (unlikely(blocked_rdev)) {
+ set_bit(STRIPE_HANDLE, &sh->state);
+ goto unlock;
+ }
pr_debug("locked=%d uptodate=%d to_read=%d"
" to_write=%d failed=%d failed_num=%d,%d\n",
s.locked, s.uptodate, s.to_read, s.to_write, s.failed,
@@ -3094,8 +3123,13 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
!test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
handle_stripe_expansion(conf, sh, &r6s);
+ unlock:
spin_unlock(&sh->lock);
+ /* wait for this device to become unblocked */
+ if (unlikely(blocked_rdev))
+ md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+
return_io(return_bi);
for (i=disks; i-- ;) {
@@ -4223,6 +4257,7 @@ static int run(mddev_t *mddev)
goto abort;
}
spin_lock_init(&conf->device_lock);
+ mddev->queue->queue_lock = &conf->device_lock;
init_waitqueue_head(&conf->wait_for_stripe);
init_waitqueue_head(&conf->wait_for_overlap);
INIT_LIST_HEAD(&conf->handle_list);
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 128bb9cd5755..7a7803b5d497 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -5,16 +5,20 @@
menu "Multimedia devices"
depends on HAS_IOMEM
+comment "Multimedia core support"
+
+#
+# V4L core and enabled API's
+#
+
config VIDEO_DEV
tristate "Video For Linux"
---help---
- Support for audio/video capture and overlay devices and FM radio
- cards. The exact capabilities of each device vary.
+ V4L core support for video capture and overlay devices, webcams and
+ AM/FM radio cards.
This kernel includes support for the new Video for Linux Two API,
- (V4L2) as well as the original system. Drivers and applications
- need to be rewritten to use V4L2, but drivers for popular cards
- and applications for most video capture functions already exist.
+ (V4L2).
Additional info and docs are available on the web at
<http://linuxtv.org>
@@ -36,8 +40,11 @@ config VIDEO_ALLOW_V4L1
default VIDEO_DEV && VIDEO_V4L2_COMMON
select VIDEO_V4L1_COMPAT
---help---
- Enables a compatibility API used by most V4L2 devices to allow
- its usage with legacy applications that supports only V4L1 api.
+ Enables drivers based on the legacy V4L1 API.
+
+ This api were developed to be used at Kernel 2.2 and 2.4, but
+ lacks support for several video standards. There are several
+ drivers at kernel that still depends on it.
If you are unsure as to whether this is required, answer Y.
@@ -46,9 +53,8 @@ config VIDEO_V4L1_COMPAT
depends on VIDEO_DEV
default VIDEO_DEV
---help---
- This api were developed to be used at Kernel 2.2 and 2.4, but
- lacks support for several video standards. There are several
- drivers at kernel that still depends on it.
+ Enables a compatibility API used by most V4L2 devices to allow
+ its usage with legacy applications that supports only V4L1 api.
Documentation for the original API is included in the file
<Documentation/video4linux/API.html>.
@@ -58,135 +64,56 @@ config VIDEO_V4L1_COMPAT
If you are unsure as to whether this is required, answer Y.
-config VIDEO_V4L2
- tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON
- default VIDEO_DEV && VIDEO_V4L2_COMMON
-
-config VIDEO_V4L1
- tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
- default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
-
-source "drivers/media/video/Kconfig"
-
-source "drivers/media/radio/Kconfig"
-
-source "drivers/media/dvb/Kconfig"
-
-source "drivers/media/common/Kconfig"
+#
+# DVB Core
+#
-config VIDEO_TUNER
- tristate
- depends on I2C
- select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
-
-menuconfig VIDEO_TUNER_CUSTOMIZE
- bool "Customize analog tuner modules to build"
- depends on VIDEO_TUNER
+config DVB_CORE
+ tristate "DVB for Linux"
+ depends on NET && INET
+ select CRC32
help
- This allows the user to deselect tuner drivers unnecessary
- for their hardware from the build. Use this option with care
- as deselecting tuner drivers which are in fact necessary will
- result in V4L devices which cannot be tuned due to lack of
- driver support
+ DVB core utility functions for device handling, software fallbacks etc.
- If unsure say N.
-
-if VIDEO_TUNER_CUSTOMIZE
-
-config TUNER_XC2028
- tristate "XCeive xc2028/xc3028 tuners"
- depends on I2C && FW_LOADER
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the xc2028/xc3028 tuners.
+ Enable this if you own a DVB/ATSC adapter and want to use it or if
+ you compile Linux for a digital SetTopBox.
-config TUNER_MT20XX
- tristate "Microtune 2032 / 2050 tuners"
- depends on I2C
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the MT2032 / MT2050 tuner.
-
-config TUNER_TDA8290
- tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
- depends on I2C
- select DVB_TDA827X
- select DVB_TDA18271
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for Philips TDA8290+8275(a) tuner.
+ Say Y when you have a DVB or an ATSC card and want to use it.
-config TUNER_TEA5761
- tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
- depends on I2C && EXPERIMENTAL
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the Philips TEA5761 radio tuner.
+ API specs and user tools are available from <http://www.linuxtv.org/>.
-config TUNER_TEA5767
- tristate "TEA 5767 radio tuner"
- depends on I2C
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the Philips TEA5767 radio tuner.
+ Please report problems regarding this support to the LinuxDVB
+ mailing list.
-config TUNER_SIMPLE
- tristate "Simple tuner support"
- depends on I2C
- select TUNER_TDA9887
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for various simple tuners.
+ If unsure say N.
-config TUNER_TDA9887
- tristate "TDA 9885/6/7 analog IF demodulator"
- depends on I2C
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for Philips TDA9885/6/7
- analog IF demodulator.
+config VIDEO_MEDIA
+ tristate
+ default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
-endif # VIDEO_TUNER_CUSTOMIZE
+comment "Multimedia drivers"
-config VIDEOBUF_GEN
- tristate
+source "drivers/media/common/Kconfig"
-config VIDEOBUF_DMA_SG
- depends on HAS_DMA
- select VIDEOBUF_GEN
- tristate
+#
+# Tuner drivers for DVB and V4L
+#
-config VIDEOBUF_VMALLOC
- select VIDEOBUF_GEN
- tristate
+source "drivers/media/common/tuners/Kconfig"
-config VIDEOBUF_DVB
- tristate
- select VIDEOBUF_GEN
- select VIDEOBUF_DMA_SG
+#
+# Video/Radio/Hybrid adapters
+#
-config VIDEO_BTCX
- tristate
+source "drivers/media/video/Kconfig"
-config VIDEO_IR_I2C
- tristate
+source "drivers/media/radio/Kconfig"
-config VIDEO_IR
- tristate
- depends on INPUT
- select VIDEO_IR_I2C if I2C
+#
+# DVB adapters
+#
-config VIDEO_TVEEPROM
- tristate
- depends on I2C
+source "drivers/media/dvb/Kconfig"
config DAB
boolean "DAB adapters"
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 7b8bb6949f5e..cc11c4c0e7e7 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -3,9 +3,11 @@
#
obj-y := common/
-obj-y += video/
+
+obj-$(CONFIG_VIDEO_MEDIA) += common/
+
+# Since hybrid devices are here, should be compiled if DVB and/or V4L
+obj-$(CONFIG_VIDEO_MEDIA) += video/
+
obj-$(CONFIG_VIDEO_DEV) += radio/
obj-$(CONFIG_DVB_CORE) += dvb/
-ifeq ($(CONFIG_DVB_CORE),)
- obj-$(CONFIG_VIDEO_TUNER) += dvb/frontends/
-endif
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 8e7448230643..351b98b9b302 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -2,6 +2,7 @@ saa7146-objs := saa7146_i2c.o saa7146_core.o
saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
+obj-y += tuners/
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
new file mode 100644
index 000000000000..d6206540476b
--- /dev/null
+++ b/drivers/media/common/tuners/Kconfig
@@ -0,0 +1,163 @@
+config MEDIA_ATTACH
+ bool "Load and attach frontend and tuner driver modules as needed"
+ depends on VIDEO_MEDIA
+ depends on MODULES
+ help
+ Remove the static dependency of DVB card drivers on all
+ frontend modules for all possible card variants. Instead,
+ allow the card drivers to only load the frontend modules
+ they require.
+
+ Also, tuner module will automatically load a tuner driver
+ when needed, for analog mode.
+
+ This saves several KBytes of memory.
+
+ Note: You will need module-init-tools v3.2 or later for this feature.
+
+ If unsure say Y.
+
+config MEDIA_TUNER
+ tristate
+ default VIDEO_MEDIA && I2C
+ depends on VIDEO_MEDIA && I2C
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
+ select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE
+
+menuconfig MEDIA_TUNER_CUSTOMIZE
+ bool "Customize analog and hybrid tuner modules to build"
+ depends on MEDIA_TUNER
+ help
+ This allows the user to deselect tuner drivers unnecessary
+ for their hardware from the build. Use this option with care
+ as deselecting tuner drivers which are in fact necessary will
+ result in V4L/DVB devices which cannot be tuned due to lack of
+ driver support
+
+ If unsure say N.
+
+if MEDIA_TUNER_CUSTOMIZE
+
+config MEDIA_TUNER_SIMPLE
+ tristate "Simple tuner support"
+ depends on VIDEO_MEDIA && I2C
+ select MEDIA_TUNER_TDA9887
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for various simple tuners.
+
+config MEDIA_TUNER_TDA8290
+ tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
+ depends on VIDEO_MEDIA && I2C
+ select MEDIA_TUNER_TDA827X
+ select MEDIA_TUNER_TDA18271
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config MEDIA_TUNER_TDA827X
+ tristate "Philips TDA827X silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA18271
+ tristate "NXP TDA18271 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA9887
+ tristate "TDA 9885/6/7 analog IF demodulator"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for Philips TDA9885/6/7
+ analog IF demodulator.
+
+config MEDIA_TUNER_TEA5761
+ tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on VIDEO_MEDIA && I2C
+ depends on EXPERIMENTAL
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config MEDIA_TUNER_TEA5767
+ tristate "TEA 5767 radio tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config MEDIA_TUNER_MT20XX
+ tristate "Microtune 2032 / 2050 tuners"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config MEDIA_TUNER_MT2060
+ tristate "Microtune MT2060 silicon IF tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon IF tuner MT2060 from Microtune.
+
+config MEDIA_TUNER_MT2266
+ tristate "Microtune MT2266 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config MEDIA_TUNER_MT2131
+ tristate "Microtune MT2131 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config MEDIA_TUNER_QT1010
+ tristate "Quantek QT1010 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner QT1010 from Quantek.
+
+config MEDIA_TUNER_XC2028
+ tristate "XCeive xc2028/xc3028 tuners"
+ depends on VIDEO_MEDIA && I2C
+ depends on HOTPLUG
+ select FW_LOADER
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the xc2028/xc3028 tuners.
+
+config MEDIA_TUNER_XC5000
+ tristate "Xceive XC5000 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ depends on HOTPLUG
+ select FW_LOADER
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner XC5000 from Xceive.
+ This device is only used inside a SiP called togther with a
+ demodulator for now.
+
+config MEDIA_TUNER_MXL5005S
+ tristate "MaxLinear MSL5005S silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner MXL5005S from MaxLinear.
+
+endif # MEDIA_TUNER_CUSTOMIZE
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
new file mode 100644
index 000000000000..55f7e6706297
--- /dev/null
+++ b/drivers/media/common/tuners/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for common V4L/DVB tuners
+#
+
+tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o
+
+obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o
+# tuner-types will be merged into tuner-simple, in the future
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o
+obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o
+obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
+obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
+obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
+obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
+obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/common/tuners/mt2060.c
index 1305b0e63ce5..1305b0e63ce5 100644
--- a/drivers/media/dvb/frontends/mt2060.c
+++ b/drivers/media/common/tuners/mt2060.c
diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/common/tuners/mt2060.h
index acba0058f519..cb60caffb6b6 100644
--- a/drivers/media/dvb/frontends/mt2060.h
+++ b/drivers/media/common/tuners/mt2060.h
@@ -30,7 +30,7 @@ struct mt2060_config {
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE))
extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
#else
static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
@@ -38,6 +38,6 @@ static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struc
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_MT2060
+#endif // CONFIG_MEDIA_TUNER_MT2060
#endif
diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h
index 5eaccdefd0b0..5eaccdefd0b0 100644
--- a/drivers/media/dvb/frontends/mt2060_priv.h
+++ b/drivers/media/common/tuners/mt2060_priv.h
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/common/tuners/mt20xx.c
index fbcb28233737..fbcb28233737 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/common/tuners/mt20xx.c
diff --git a/drivers/media/video/mt20xx.h b/drivers/media/common/tuners/mt20xx.h
index aa848e14ce5e..259553a24903 100644
--- a/drivers/media/video/mt20xx.h
+++ b/drivers/media/common/tuners/mt20xx.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE))
extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/common/tuners/mt2131.c
index e254bcfc2efb..e254bcfc2efb 100644
--- a/drivers/media/dvb/frontends/mt2131.c
+++ b/drivers/media/common/tuners/mt2131.c
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/common/tuners/mt2131.h
index 606d8576bc98..cd8376f6f7b4 100644
--- a/drivers/media/dvb/frontends/mt2131.h
+++ b/drivers/media/common/tuners/mt2131.h
@@ -30,7 +30,7 @@ struct mt2131_config {
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE))
extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mt2131_config *cfg,
@@ -44,7 +44,7 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif /* CONFIG_DVB_TUNER_MT2131 */
+#endif /* CONFIG_MEDIA_TUNER_MT2131 */
#endif /* __MT2131_H__ */
diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
index e930759c2c00..e930759c2c00 100644
--- a/drivers/media/dvb/frontends/mt2131_priv.h
+++ b/drivers/media/common/tuners/mt2131_priv.h
diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/common/tuners/mt2266.c
index 54b18f94b14b..54b18f94b14b 100644
--- a/drivers/media/dvb/frontends/mt2266.c
+++ b/drivers/media/common/tuners/mt2266.c
diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/common/tuners/mt2266.h
index c5113efe333c..4d083882d044 100644
--- a/drivers/media/dvb/frontends/mt2266.h
+++ b/drivers/media/common/tuners/mt2266.h
@@ -24,7 +24,7 @@ struct mt2266_config {
u8 i2c_address;
};
-#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE))
extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
#else
static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
@@ -32,6 +32,6 @@ static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struc
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_MT2266
+#endif // CONFIG_MEDIA_TUNER_MT2266
#endif
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
new file mode 100644
index 000000000000..5d05b5390f66
--- /dev/null
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -0,0 +1,4110 @@
+/*
+ MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
+
+ Copyright (C) 2008 MaxLinear
+ Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Functions:
+ mxl5005s_reset()
+ mxl5005s_writereg()
+ mxl5005s_writeregs()
+ mxl5005s_init()
+ mxl5005s_reconfigure()
+ mxl5005s_AssignTunerMode()
+ mxl5005s_set_params()
+ mxl5005s_get_frequency()
+ mxl5005s_get_bandwidth()
+ mxl5005s_release()
+ mxl5005s_attach()
+
+ Copyright (C) 2008 Realtek
+ Copyright (C) 2008 Jan Hoogenraad
+ Functions:
+ mxl5005s_SetRfFreqHz()
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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.
+
+*/
+
+/*
+ History of this driver (Steven Toth):
+ I was given a public release of a linux driver that included
+ support for the MaxLinear MXL5005S silicon tuner. Analysis of
+ the tuner driver showed clearly three things.
+
+ 1. The tuner driver didn't support the LinuxTV tuner API
+ so the code Realtek added had to be removed.
+
+ 2. A significant amount of the driver is reference driver code
+ from MaxLinear, I felt it was important to identify and
+ preserve this.
+
+ 3. New code has to be added to interface correctly with the
+ LinuxTV API, as a regular kernel module.
+
+ Other than the reference driver enum's, I've clearly marked
+ sections of the code and retained the copyright of the
+ respective owners.
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "mxl5005s.h"
+
+static int debug;
+
+#define dprintk(level, arg...) do { \
+ if (level <= debug) \
+ printk(arg); \
+ } while (0)
+
+#define TUNER_REGS_NUM 104
+#define INITCTRL_NUM 40
+
+#ifdef _MXL_PRODUCTION
+#define CHCTRL_NUM 39
+#else
+#define CHCTRL_NUM 36
+#endif
+
+#define MXLCTRL_NUM 189
+#define MASTER_CONTROL_ADDR 9
+
+/* Enumeration of Master Control Register State */
+enum master_control_state {
+ MC_LOAD_START = 1,
+ MC_POWER_DOWN,
+ MC_SYNTH_RESET,
+ MC_SEQ_OFF
+};
+
+/* Enumeration of MXL5005 Tuner Modulation Type */
+enum {
+ MXL_DEFAULT_MODULATION = 0,
+ MXL_DVBT,
+ MXL_ATSC,
+ MXL_QAM,
+ MXL_ANALOG_CABLE,
+ MXL_ANALOG_OTA
+} tuner_modu_type;
+
+/* MXL5005 Tuner Register Struct */
+struct TunerReg {
+ u16 Reg_Num; /* Tuner Register Address */
+ u16 Reg_Val; /* Current sw programmed value waiting to be writen */
+};
+
+enum {
+ /* Initialization Control Names */
+ DN_IQTN_AMP_CUT = 1, /* 1 */
+ BB_MODE, /* 2 */
+ BB_BUF, /* 3 */
+ BB_BUF_OA, /* 4 */
+ BB_ALPF_BANDSELECT, /* 5 */
+ BB_IQSWAP, /* 6 */
+ BB_DLPF_BANDSEL, /* 7 */
+ RFSYN_CHP_GAIN, /* 8 */
+ RFSYN_EN_CHP_HIGAIN, /* 9 */
+ AGC_IF, /* 10 */
+ AGC_RF, /* 11 */
+ IF_DIVVAL, /* 12 */
+ IF_VCO_BIAS, /* 13 */
+ CHCAL_INT_MOD_IF, /* 14 */
+ CHCAL_FRAC_MOD_IF, /* 15 */
+ DRV_RES_SEL, /* 16 */
+ I_DRIVER, /* 17 */
+ EN_AAF, /* 18 */
+ EN_3P, /* 19 */
+ EN_AUX_3P, /* 20 */
+ SEL_AAF_BAND, /* 21 */
+ SEQ_ENCLK16_CLK_OUT, /* 22 */
+ SEQ_SEL4_16B, /* 23 */
+ XTAL_CAPSELECT, /* 24 */
+ IF_SEL_DBL, /* 25 */
+ RFSYN_R_DIV, /* 26 */
+ SEQ_EXTSYNTHCALIF, /* 27 */
+ SEQ_EXTDCCAL, /* 28 */
+ AGC_EN_RSSI, /* 29 */
+ RFA_ENCLKRFAGC, /* 30 */
+ RFA_RSSI_REFH, /* 31 */
+ RFA_RSSI_REF, /* 32 */
+ RFA_RSSI_REFL, /* 33 */
+ RFA_FLR, /* 34 */
+ RFA_CEIL, /* 35 */
+ SEQ_EXTIQFSMPULSE, /* 36 */
+ OVERRIDE_1, /* 37 */
+ BB_INITSTATE_DLPF_TUNE, /* 38 */
+ TG_R_DIV, /* 39 */
+ EN_CHP_LIN_B, /* 40 */
+
+ /* Channel Change Control Names */
+ DN_POLY = 51, /* 51 */
+ DN_RFGAIN, /* 52 */
+ DN_CAP_RFLPF, /* 53 */
+ DN_EN_VHFUHFBAR, /* 54 */
+ DN_GAIN_ADJUST, /* 55 */
+ DN_IQTNBUF_AMP, /* 56 */
+ DN_IQTNGNBFBIAS_BST, /* 57 */
+ RFSYN_EN_OUTMUX, /* 58 */
+ RFSYN_SEL_VCO_OUT, /* 59 */
+ RFSYN_SEL_VCO_HI, /* 60 */
+ RFSYN_SEL_DIVM, /* 61 */
+ RFSYN_RF_DIV_BIAS, /* 62 */
+ DN_SEL_FREQ, /* 63 */
+ RFSYN_VCO_BIAS, /* 64 */
+ CHCAL_INT_MOD_RF, /* 65 */
+ CHCAL_FRAC_MOD_RF, /* 66 */
+ RFSYN_LPF_R, /* 67 */
+ CHCAL_EN_INT_RF, /* 68 */
+ TG_LO_DIVVAL, /* 69 */
+ TG_LO_SELVAL, /* 70 */
+ TG_DIV_VAL, /* 71 */
+ TG_VCO_BIAS, /* 72 */
+ SEQ_EXTPOWERUP, /* 73 */
+ OVERRIDE_2, /* 74 */
+ OVERRIDE_3, /* 75 */
+ OVERRIDE_4, /* 76 */
+ SEQ_FSM_PULSE, /* 77 */
+ GPIO_4B, /* 78 */
+ GPIO_3B, /* 79 */
+ GPIO_4, /* 80 */
+ GPIO_3, /* 81 */
+ GPIO_1B, /* 82 */
+ DAC_A_ENABLE, /* 83 */
+ DAC_B_ENABLE, /* 84 */
+ DAC_DIN_A, /* 85 */
+ DAC_DIN_B, /* 86 */
+#ifdef _MXL_PRODUCTION
+ RFSYN_EN_DIV, /* 87 */
+ RFSYN_DIVM, /* 88 */
+ DN_BYPASS_AGC_I2C /* 89 */
+#endif
+} MXL5005_ControlName;
+
+/*
+ * The following context is source code provided by MaxLinear.
+ * MaxLinear source code - Common_MXL.h (?)
+ */
+
+/* Constants */
+#define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104
+#define MXL5005S_LATCH_BYTE 0xfe
+
+/* Register address, MSB, and LSB */
+#define MXL5005S_BB_IQSWAP_ADDR 59
+#define MXL5005S_BB_IQSWAP_MSB 0
+#define MXL5005S_BB_IQSWAP_LSB 0
+
+#define MXL5005S_BB_DLPF_BANDSEL_ADDR 53
+#define MXL5005S_BB_DLPF_BANDSEL_MSB 4
+#define MXL5005S_BB_DLPF_BANDSEL_LSB 3
+
+/* Standard modes */
+enum {
+ MXL5005S_STANDARD_DVBT,
+ MXL5005S_STANDARD_ATSC,
+};
+#define MXL5005S_STANDARD_MODE_NUM 2
+
+/* Bandwidth modes */
+enum {
+ MXL5005S_BANDWIDTH_6MHZ = 6000000,
+ MXL5005S_BANDWIDTH_7MHZ = 7000000,
+ MXL5005S_BANDWIDTH_8MHZ = 8000000,
+};
+#define MXL5005S_BANDWIDTH_MODE_NUM 3
+
+/* MXL5005 Tuner Control Struct */
+struct TunerControl {
+ u16 Ctrl_Num; /* Control Number */
+ u16 size; /* Number of bits to represent Value */
+ u16 addr[25]; /* Array of Tuner Register Address for each bit pos */
+ u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */
+ u16 val[25]; /* Binary representation of Value */
+};
+
+/* MXL5005 Tuner Struct */
+struct mxl5005s_state {
+ u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */
+ u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */
+ u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */
+ u32 IF_OUT; /* Desired IF Out Frequency */
+ u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */
+ u32 RF_IN; /* RF Input Frequency */
+ u32 Fxtal; /* XTAL Frequency */
+ u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */
+ u16 TOP; /* Value: take over point */
+ u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */
+ u8 DIV_OUT; /* 4MHz or 16MHz */
+ u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */
+ u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */
+
+ /* Modulation Type; */
+ /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
+ u8 Mod_Type;
+
+ /* Tracking Filter Type */
+ /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
+ u8 TF_Type;
+
+ /* Calculated Settings */
+ u32 RF_LO; /* Synth RF LO Frequency */
+ u32 IF_LO; /* Synth IF LO Frequency */
+ u32 TG_LO; /* Synth TG_LO Frequency */
+
+ /* Pointers to ControlName Arrays */
+ u16 Init_Ctrl_Num; /* Number of INIT Control Names */
+ struct TunerControl
+ Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */
+
+ u16 CH_Ctrl_Num; /* Number of CH Control Names */
+ struct TunerControl
+ CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */
+
+ u16 MXL_Ctrl_Num; /* Number of MXL Control Names */
+ struct TunerControl
+ MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */
+
+ /* Pointer to Tuner Register Array */
+ u16 TunerRegs_Num; /* Number of Tuner Registers */
+ struct TunerReg
+ TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */
+
+ /* Linux driver framework specific */
+ struct mxl5005s_config *config;
+ struct dvb_frontend *frontend;
+ struct i2c_adapter *i2c;
+
+ /* Cache values */
+ u32 current_mode;
+
+};
+
+static u16 MXL_GetMasterControl(u8 *MasterReg, int state);
+static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value);
+static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value);
+static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
+ u8 bitVal);
+static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum,
+ u8 *RegVal, int *count);
+static u32 MXL_Ceiling(u32 value, u32 resolution);
+static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal);
+static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
+ u32 value, u16 controlGroup);
+static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val);
+static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
+ u8 *RegVal, int *count);
+static u32 MXL_GetXtalInt(u32 Xtal_Freq);
+static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
+static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
+static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
+static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
+ u8 *RegVal, int *count);
+static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
+ u8 *datatable, u8 len);
+static u16 MXL_IFSynthInit(struct dvb_frontend *fe);
+static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
+ u32 bandwidth);
+static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
+ u32 bandwidth);
+
+/* ----------------------------------------------------------------
+ * Begin: Custom code salvaged from the Realtek driver.
+ * Copyright (C) 2008 Realtek
+ * Copyright (C) 2008 Jan Hoogenraad
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * Released by Realtek under GPLv2.
+ * Thanks to Realtek for a lot of support we received !
+ *
+ * Revision: 080314 - original version
+ */
+
+static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+ unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+ int TableLen;
+
+ u32 IfDivval = 0;
+ unsigned char MasterControlByte;
+
+ dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz);
+
+ /* Set MxL5005S tuner RF frequency according to example code. */
+
+ /* Tuner RF frequency setting stage 0 */
+ MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
+ AddrTable[0] = MASTER_CONTROL_ADDR;
+ ByteTable[0] |= state->config->AgcMasterByte;
+
+ mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
+
+ /* Tuner RF frequency setting stage 1 */
+ MXL_TuneRF(fe, RfFreqHz);
+
+ MXL_ControlRead(fe, IF_DIVVAL, &IfDivval);
+
+ MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0);
+ MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1);
+ MXL_ControlWrite(fe, IF_DIVVAL, 8);
+ MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen);
+
+ MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
+ AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
+ ByteTable[TableLen] = MasterControlByte |
+ state->config->AgcMasterByte;
+ TableLen += 1;
+
+ mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+ /* Wait 30 ms. */
+ msleep(150);
+
+ /* Tuner RF frequency setting stage 2 */
+ MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1);
+ MXL_ControlWrite(fe, IF_DIVVAL, IfDivval);
+ MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen);
+
+ MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START);
+ AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
+ ByteTable[TableLen] = MasterControlByte |
+ state->config->AgcMasterByte ;
+ TableLen += 1;
+
+ mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+ msleep(100);
+
+ return 0;
+}
+/* End: Custom code taken from the Realtek driver */
+
+/* ----------------------------------------------------------------
+ * Begin: Reference driver code found in the Realtek driver.
+ * Copyright (C) 2008 MaxLinear
+ */
+static u16 MXL5005_RegisterInit(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ state->TunerRegs_Num = TUNER_REGS_NUM ;
+
+ state->TunerRegs[0].Reg_Num = 9 ;
+ state->TunerRegs[0].Reg_Val = 0x40 ;
+
+ state->TunerRegs[1].Reg_Num = 11 ;
+ state->TunerRegs[1].Reg_Val = 0x19 ;
+
+ state->TunerRegs[2].Reg_Num = 12 ;
+ state->TunerRegs[2].Reg_Val = 0x60 ;
+
+ state->TunerRegs[3].Reg_Num = 13 ;
+ state->TunerRegs[3].Reg_Val = 0x00 ;
+
+ state->TunerRegs[4].Reg_Num = 14 ;
+ state->TunerRegs[4].Reg_Val = 0x00 ;
+
+ state->TunerRegs[5].Reg_Num = 15 ;
+ state->TunerRegs[5].Reg_Val = 0xC0 ;
+
+ state->TunerRegs[6].Reg_Num = 16 ;
+ state->TunerRegs[6].Reg_Val = 0x00 ;
+
+ state->TunerRegs[7].Reg_Num = 17 ;
+ state->TunerRegs[7].Reg_Val = 0x00 ;
+
+ state->TunerRegs[8].Reg_Num = 18 ;
+ state->TunerRegs[8].Reg_Val = 0x00 ;
+
+ state->TunerRegs[9].Reg_Num = 19 ;
+ state->TunerRegs[9].Reg_Val = 0x34 ;
+
+ state->TunerRegs[10].Reg_Num = 21 ;
+ state->TunerRegs[10].Reg_Val = 0x00 ;
+
+ state->TunerRegs[11].Reg_Num = 22 ;
+ state->TunerRegs[11].Reg_Val = 0x6B ;
+
+ state->TunerRegs[12].Reg_Num = 23 ;
+ state->TunerRegs[12].Reg_Val = 0x35 ;
+
+ state->TunerRegs[13].Reg_Num = 24 ;
+ state->TunerRegs[13].Reg_Val = 0x70 ;
+
+ state->TunerRegs[14].Reg_Num = 25 ;
+ state->TunerRegs[14].Reg_Val = 0x3E ;
+
+ state->TunerRegs[15].Reg_Num = 26 ;
+ state->TunerRegs[15].Reg_Val = 0x82 ;
+
+ state->TunerRegs[16].Reg_Num = 31 ;
+ state->TunerRegs[16].Reg_Val = 0x00 ;
+
+ state->TunerRegs[17].Reg_Num = 32 ;
+ state->TunerRegs[17].Reg_Val = 0x40 ;
+
+ state->TunerRegs[18].Reg_Num = 33 ;
+ state->TunerRegs[18].Reg_Val = 0x53 ;
+
+ state->TunerRegs[19].Reg_Num = 34 ;
+ state->TunerRegs[19].Reg_Val = 0x81 ;
+
+ state->TunerRegs[20].Reg_Num = 35 ;
+ state->TunerRegs[20].Reg_Val = 0xC9 ;
+
+ state->TunerRegs[21].Reg_Num = 36 ;
+ state->TunerRegs[21].Reg_Val = 0x01 ;
+
+ state->TunerRegs[22].Reg_Num = 37 ;
+ state->TunerRegs[22].Reg_Val = 0x00 ;
+
+ state->TunerRegs[23].Reg_Num = 41 ;
+ state->TunerRegs[23].Reg_Val = 0x00 ;
+
+ state->TunerRegs[24].Reg_Num = 42 ;
+ state->TunerRegs[24].Reg_Val = 0xF8 ;
+
+ state->TunerRegs[25].Reg_Num = 43 ;
+ state->TunerRegs[25].Reg_Val = 0x43 ;
+
+ state->TunerRegs[26].Reg_Num = 44 ;
+ state->TunerRegs[26].Reg_Val = 0x20 ;
+
+ state->TunerRegs[27].Reg_Num = 45 ;
+ state->TunerRegs[27].Reg_Val = 0x80 ;
+
+ state->TunerRegs[28].Reg_Num = 46 ;
+ state->TunerRegs[28].Reg_Val = 0x88 ;
+
+ state->TunerRegs[29].Reg_Num = 47 ;
+ state->TunerRegs[29].Reg_Val = 0x86 ;
+
+ state->TunerRegs[30].Reg_Num = 48 ;
+ state->TunerRegs[30].Reg_Val = 0x00 ;
+
+ state->TunerRegs[31].Reg_Num = 49 ;
+ state->TunerRegs[31].Reg_Val = 0x00 ;
+
+ state->TunerRegs[32].Reg_Num = 53 ;
+ state->TunerRegs[32].Reg_Val = 0x94 ;
+
+ state->TunerRegs[33].Reg_Num = 54 ;
+ state->TunerRegs[33].Reg_Val = 0xFA ;
+
+ state->TunerRegs[34].Reg_Num = 55 ;
+ state->TunerRegs[34].Reg_Val = 0x92 ;
+
+ state->TunerRegs[35].Reg_Num = 56 ;
+ state->TunerRegs[35].Reg_Val = 0x80 ;
+
+ state->TunerRegs[36].Reg_Num = 57 ;
+ state->TunerRegs[36].Reg_Val = 0x41 ;
+
+ state->TunerRegs[37].Reg_Num = 58 ;
+ state->TunerRegs[37].Reg_Val = 0xDB ;
+
+ state->TunerRegs[38].Reg_Num = 59 ;
+ state->TunerRegs[38].Reg_Val = 0x00 ;
+
+ state->TunerRegs[39].Reg_Num = 60 ;
+ state->TunerRegs[39].Reg_Val = 0x00 ;
+
+ state->TunerRegs[40].Reg_Num = 61 ;
+ state->TunerRegs[40].Reg_Val = 0x00 ;
+
+ state->TunerRegs[41].Reg_Num = 62 ;
+ state->TunerRegs[41].Reg_Val = 0x00 ;
+
+ state->TunerRegs[42].Reg_Num = 65 ;
+ state->TunerRegs[42].Reg_Val = 0xF8 ;
+
+ state->TunerRegs[43].Reg_Num = 66 ;
+ state->TunerRegs[43].Reg_Val = 0xE4 ;
+
+ state->TunerRegs[44].Reg_Num = 67 ;
+ state->TunerRegs[44].Reg_Val = 0x90 ;
+
+ state->TunerRegs[45].Reg_Num = 68 ;
+ state->TunerRegs[45].Reg_Val = 0xC0 ;
+
+ state->TunerRegs[46].Reg_Num = 69 ;
+ state->TunerRegs[46].Reg_Val = 0x01 ;
+
+ state->TunerRegs[47].Reg_Num = 70 ;
+ state->TunerRegs[47].Reg_Val = 0x50 ;
+
+ state->TunerRegs[48].Reg_Num = 71 ;
+ state->TunerRegs[48].Reg_Val = 0x06 ;
+
+ state->TunerRegs[49].Reg_Num = 72 ;
+ state->TunerRegs[49].Reg_Val = 0x00 ;
+
+ state->TunerRegs[50].Reg_Num = 73 ;
+ state->TunerRegs[50].Reg_Val = 0x20 ;
+
+ state->TunerRegs[51].Reg_Num = 76 ;
+ state->TunerRegs[51].Reg_Val = 0xBB ;
+
+ state->TunerRegs[52].Reg_Num = 77 ;
+ state->TunerRegs[52].Reg_Val = 0x13 ;
+
+ state->TunerRegs[53].Reg_Num = 81 ;
+ state->TunerRegs[53].Reg_Val = 0x04 ;
+
+ state->TunerRegs[54].Reg_Num = 82 ;
+ state->TunerRegs[54].Reg_Val = 0x75 ;
+
+ state->TunerRegs[55].Reg_Num = 83 ;
+ state->TunerRegs[55].Reg_Val = 0x00 ;
+
+ state->TunerRegs[56].Reg_Num = 84 ;
+ state->TunerRegs[56].Reg_Val = 0x00 ;
+
+ state->TunerRegs[57].Reg_Num = 85 ;
+ state->TunerRegs[57].Reg_Val = 0x00 ;
+
+ state->TunerRegs[58].Reg_Num = 91 ;
+ state->TunerRegs[58].Reg_Val = 0x70 ;
+
+ state->TunerRegs[59].Reg_Num = 92 ;
+ state->TunerRegs[59].Reg_Val = 0x00 ;
+
+ state->TunerRegs[60].Reg_Num = 93 ;
+ state->TunerRegs[60].Reg_Val = 0x00 ;
+
+ state->TunerRegs[61].Reg_Num = 94 ;
+ state->TunerRegs[61].Reg_Val = 0x00 ;
+
+ state->TunerRegs[62].Reg_Num = 95 ;
+ state->TunerRegs[62].Reg_Val = 0x0C ;
+
+ state->TunerRegs[63].Reg_Num = 96 ;
+ state->TunerRegs[63].Reg_Val = 0x00 ;
+
+ state->TunerRegs[64].Reg_Num = 97 ;
+ state->TunerRegs[64].Reg_Val = 0x00 ;
+
+ state->TunerRegs[65].Reg_Num = 98 ;
+ state->TunerRegs[65].Reg_Val = 0xE2 ;
+
+ state->TunerRegs[66].Reg_Num = 99 ;
+ state->TunerRegs[66].Reg_Val = 0x00 ;
+
+ state->TunerRegs[67].Reg_Num = 100 ;
+ state->TunerRegs[67].Reg_Val = 0x00 ;
+
+ state->TunerRegs[68].Reg_Num = 101 ;
+ state->TunerRegs[68].Reg_Val = 0x12 ;
+
+ state->TunerRegs[69].Reg_Num = 102 ;
+ state->TunerRegs[69].Reg_Val = 0x80 ;
+
+ state->TunerRegs[70].Reg_Num = 103 ;
+ state->TunerRegs[70].Reg_Val = 0x32 ;
+
+ state->TunerRegs[71].Reg_Num = 104 ;
+ state->TunerRegs[71].Reg_Val = 0xB4 ;
+
+ state->TunerRegs[72].Reg_Num = 105 ;
+ state->TunerRegs[72].Reg_Val = 0x60 ;
+
+ state->TunerRegs[73].Reg_Num = 106 ;
+ state->TunerRegs[73].Reg_Val = 0x83 ;
+
+ state->TunerRegs[74].Reg_Num = 107 ;
+ state->TunerRegs[74].Reg_Val = 0x84 ;
+
+ state->TunerRegs[75].Reg_Num = 108 ;
+ state->TunerRegs[75].Reg_Val = 0x9C ;
+
+ state->TunerRegs[76].Reg_Num = 109 ;
+ state->TunerRegs[76].Reg_Val = 0x02 ;
+
+ state->TunerRegs[77].Reg_Num = 110 ;
+ state->TunerRegs[77].Reg_Val = 0x81 ;
+
+ state->TunerRegs[78].Reg_Num = 111 ;
+ state->TunerRegs[78].Reg_Val = 0xC0 ;
+
+ state->TunerRegs[79].Reg_Num = 112 ;
+ state->TunerRegs[79].Reg_Val = 0x10 ;
+
+ state->TunerRegs[80].Reg_Num = 131 ;
+ state->TunerRegs[80].Reg_Val = 0x8A ;
+
+ state->TunerRegs[81].Reg_Num = 132 ;
+ state->TunerRegs[81].Reg_Val = 0x10 ;
+
+ state->TunerRegs[82].Reg_Num = 133 ;
+ state->TunerRegs[82].Reg_Val = 0x24 ;
+
+ state->TunerRegs[83].Reg_Num = 134 ;
+ state->TunerRegs[83].Reg_Val = 0x00 ;
+
+ state->TunerRegs[84].Reg_Num = 135 ;
+ state->TunerRegs[84].Reg_Val = 0x00 ;
+
+ state->TunerRegs[85].Reg_Num = 136 ;
+ state->TunerRegs[85].Reg_Val = 0x7E ;
+
+ state->TunerRegs[86].Reg_Num = 137 ;
+ state->TunerRegs[86].Reg_Val = 0x40 ;
+
+ state->TunerRegs[87].Reg_Num = 138 ;
+ state->TunerRegs[87].Reg_Val = 0x38 ;
+
+ state->TunerRegs[88].Reg_Num = 146 ;
+ state->TunerRegs[88].Reg_Val = 0xF6 ;
+
+ state->TunerRegs[89].Reg_Num = 147 ;
+ state->TunerRegs[89].Reg_Val = 0x1A ;
+
+ state->TunerRegs[90].Reg_Num = 148 ;
+ state->TunerRegs[90].Reg_Val = 0x62 ;
+
+ state->TunerRegs[91].Reg_Num = 149 ;
+ state->TunerRegs[91].Reg_Val = 0x33 ;
+
+ state->TunerRegs[92].Reg_Num = 150 ;
+ state->TunerRegs[92].Reg_Val = 0x80 ;
+
+ state->TunerRegs[93].Reg_Num = 156 ;
+ state->TunerRegs[93].Reg_Val = 0x56 ;
+
+ state->TunerRegs[94].Reg_Num = 157 ;
+ state->TunerRegs[94].Reg_Val = 0x17 ;
+
+ state->TunerRegs[95].Reg_Num = 158 ;
+ state->TunerRegs[95].Reg_Val = 0xA9 ;
+
+ state->TunerRegs[96].Reg_Num = 159 ;
+ state->TunerRegs[96].Reg_Val = 0x00 ;
+
+ state->TunerRegs[97].Reg_Num = 160 ;
+ state->TunerRegs[97].Reg_Val = 0x00 ;
+
+ state->TunerRegs[98].Reg_Num = 161 ;
+ state->TunerRegs[98].Reg_Val = 0x00 ;
+
+ state->TunerRegs[99].Reg_Num = 162 ;
+ state->TunerRegs[99].Reg_Val = 0x40 ;
+
+ state->TunerRegs[100].Reg_Num = 166 ;
+ state->TunerRegs[100].Reg_Val = 0xAE ;
+
+ state->TunerRegs[101].Reg_Num = 167 ;
+ state->TunerRegs[101].Reg_Val = 0x1B ;
+
+ state->TunerRegs[102].Reg_Num = 168 ;
+ state->TunerRegs[102].Reg_Val = 0xF2 ;
+
+ state->TunerRegs[103].Reg_Num = 195 ;
+ state->TunerRegs[103].Reg_Val = 0x00 ;
+
+ return 0 ;
+}
+
+static u16 MXL5005_ControlInit(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ state->Init_Ctrl_Num = INITCTRL_NUM;
+
+ state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ;
+ state->Init_Ctrl[0].size = 1 ;
+ state->Init_Ctrl[0].addr[0] = 73;
+ state->Init_Ctrl[0].bit[0] = 7;
+ state->Init_Ctrl[0].val[0] = 0;
+
+ state->Init_Ctrl[1].Ctrl_Num = BB_MODE ;
+ state->Init_Ctrl[1].size = 1 ;
+ state->Init_Ctrl[1].addr[0] = 53;
+ state->Init_Ctrl[1].bit[0] = 2;
+ state->Init_Ctrl[1].val[0] = 1;
+
+ state->Init_Ctrl[2].Ctrl_Num = BB_BUF ;
+ state->Init_Ctrl[2].size = 2 ;
+ state->Init_Ctrl[2].addr[0] = 53;
+ state->Init_Ctrl[2].bit[0] = 1;
+ state->Init_Ctrl[2].val[0] = 0;
+ state->Init_Ctrl[2].addr[1] = 57;
+ state->Init_Ctrl[2].bit[1] = 0;
+ state->Init_Ctrl[2].val[1] = 1;
+
+ state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ;
+ state->Init_Ctrl[3].size = 1 ;
+ state->Init_Ctrl[3].addr[0] = 53;
+ state->Init_Ctrl[3].bit[0] = 0;
+ state->Init_Ctrl[3].val[0] = 0;
+
+ state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ;
+ state->Init_Ctrl[4].size = 3 ;
+ state->Init_Ctrl[4].addr[0] = 53;
+ state->Init_Ctrl[4].bit[0] = 5;
+ state->Init_Ctrl[4].val[0] = 0;
+ state->Init_Ctrl[4].addr[1] = 53;
+ state->Init_Ctrl[4].bit[1] = 6;
+ state->Init_Ctrl[4].val[1] = 0;
+ state->Init_Ctrl[4].addr[2] = 53;
+ state->Init_Ctrl[4].bit[2] = 7;
+ state->Init_Ctrl[4].val[2] = 1;
+
+ state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ;
+ state->Init_Ctrl[5].size = 1 ;
+ state->Init_Ctrl[5].addr[0] = 59;
+ state->Init_Ctrl[5].bit[0] = 0;
+ state->Init_Ctrl[5].val[0] = 0;
+
+ state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ;
+ state->Init_Ctrl[6].size = 2 ;
+ state->Init_Ctrl[6].addr[0] = 53;
+ state->Init_Ctrl[6].bit[0] = 3;
+ state->Init_Ctrl[6].val[0] = 0;
+ state->Init_Ctrl[6].addr[1] = 53;
+ state->Init_Ctrl[6].bit[1] = 4;
+ state->Init_Ctrl[6].val[1] = 1;
+
+ state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ;
+ state->Init_Ctrl[7].size = 4 ;
+ state->Init_Ctrl[7].addr[0] = 22;
+ state->Init_Ctrl[7].bit[0] = 4;
+ state->Init_Ctrl[7].val[0] = 0;
+ state->Init_Ctrl[7].addr[1] = 22;
+ state->Init_Ctrl[7].bit[1] = 5;
+ state->Init_Ctrl[7].val[1] = 1;
+ state->Init_Ctrl[7].addr[2] = 22;
+ state->Init_Ctrl[7].bit[2] = 6;
+ state->Init_Ctrl[7].val[2] = 1;
+ state->Init_Ctrl[7].addr[3] = 22;
+ state->Init_Ctrl[7].bit[3] = 7;
+ state->Init_Ctrl[7].val[3] = 0;
+
+ state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ;
+ state->Init_Ctrl[8].size = 1 ;
+ state->Init_Ctrl[8].addr[0] = 22;
+ state->Init_Ctrl[8].bit[0] = 2;
+ state->Init_Ctrl[8].val[0] = 0;
+
+ state->Init_Ctrl[9].Ctrl_Num = AGC_IF ;
+ state->Init_Ctrl[9].size = 4 ;
+ state->Init_Ctrl[9].addr[0] = 76;
+ state->Init_Ctrl[9].bit[0] = 0;
+ state->Init_Ctrl[9].val[0] = 1;
+ state->Init_Ctrl[9].addr[1] = 76;
+ state->Init_Ctrl[9].bit[1] = 1;
+ state->Init_Ctrl[9].val[1] = 1;
+ state->Init_Ctrl[9].addr[2] = 76;
+ state->Init_Ctrl[9].bit[2] = 2;
+ state->Init_Ctrl[9].val[2] = 0;
+ state->Init_Ctrl[9].addr[3] = 76;
+ state->Init_Ctrl[9].bit[3] = 3;
+ state->Init_Ctrl[9].val[3] = 1;
+
+ state->Init_Ctrl[10].Ctrl_Num = AGC_RF ;
+ state->Init_Ctrl[10].size = 4 ;
+ state->Init_Ctrl[10].addr[0] = 76;
+ state->Init_Ctrl[10].bit[0] = 4;
+ state->Init_Ctrl[10].val[0] = 1;
+ state->Init_Ctrl[10].addr[1] = 76;
+ state->Init_Ctrl[10].bit[1] = 5;
+ state->Init_Ctrl[10].val[1] = 1;
+ state->Init_Ctrl[10].addr[2] = 76;
+ state->Init_Ctrl[10].bit[2] = 6;
+ state->Init_Ctrl[10].val[2] = 0;
+ state->Init_Ctrl[10].addr[3] = 76;
+ state->Init_Ctrl[10].bit[3] = 7;
+ state->Init_Ctrl[10].val[3] = 1;
+
+ state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ;
+ state->Init_Ctrl[11].size = 5 ;
+ state->Init_Ctrl[11].addr[0] = 43;
+ state->Init_Ctrl[11].bit[0] = 3;
+ state->Init_Ctrl[11].val[0] = 0;
+ state->Init_Ctrl[11].addr[1] = 43;
+ state->Init_Ctrl[11].bit[1] = 4;
+ state->Init_Ctrl[11].val[1] = 0;
+ state->Init_Ctrl[11].addr[2] = 43;
+ state->Init_Ctrl[11].bit[2] = 5;
+ state->Init_Ctrl[11].val[2] = 0;
+ state->Init_Ctrl[11].addr[3] = 43;
+ state->Init_Ctrl[11].bit[3] = 6;
+ state->Init_Ctrl[11].val[3] = 1;
+ state->Init_Ctrl[11].addr[4] = 43;
+ state->Init_Ctrl[11].bit[4] = 7;
+ state->Init_Ctrl[11].val[4] = 0;
+
+ state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ;
+ state->Init_Ctrl[12].size = 6 ;
+ state->Init_Ctrl[12].addr[0] = 44;
+ state->Init_Ctrl[12].bit[0] = 2;
+ state->Init_Ctrl[12].val[0] = 0;
+ state->Init_Ctrl[12].addr[1] = 44;
+ state->Init_Ctrl[12].bit[1] = 3;
+ state->Init_Ctrl[12].val[1] = 0;
+ state->Init_Ctrl[12].addr[2] = 44;
+ state->Init_Ctrl[12].bit[2] = 4;
+ state->Init_Ctrl[12].val[2] = 0;
+ state->Init_Ctrl[12].addr[3] = 44;
+ state->Init_Ctrl[12].bit[3] = 5;
+ state->Init_Ctrl[12].val[3] = 1;
+ state->Init_Ctrl[12].addr[4] = 44;
+ state->Init_Ctrl[12].bit[4] = 6;
+ state->Init_Ctrl[12].val[4] = 0;
+ state->Init_Ctrl[12].addr[5] = 44;
+ state->Init_Ctrl[12].bit[5] = 7;
+ state->Init_Ctrl[12].val[5] = 0;
+
+ state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ;
+ state->Init_Ctrl[13].size = 7 ;
+ state->Init_Ctrl[13].addr[0] = 11;
+ state->Init_Ctrl[13].bit[0] = 0;
+ state->Init_Ctrl[13].val[0] = 1;
+ state->Init_Ctrl[13].addr[1] = 11;
+ state->Init_Ctrl[13].bit[1] = 1;
+ state->Init_Ctrl[13].val[1] = 0;
+ state->Init_Ctrl[13].addr[2] = 11;
+ state->Init_Ctrl[13].bit[2] = 2;
+ state->Init_Ctrl[13].val[2] = 0;
+ state->Init_Ctrl[13].addr[3] = 11;
+ state->Init_Ctrl[13].bit[3] = 3;
+ state->Init_Ctrl[13].val[3] = 1;
+ state->Init_Ctrl[13].addr[4] = 11;
+ state->Init_Ctrl[13].bit[4] = 4;
+ state->Init_Ctrl[13].val[4] = 1;
+ state->Init_Ctrl[13].addr[5] = 11;
+ state->Init_Ctrl[13].bit[5] = 5;
+ state->Init_Ctrl[13].val[5] = 0;
+ state->Init_Ctrl[13].addr[6] = 11;
+ state->Init_Ctrl[13].bit[6] = 6;
+ state->Init_Ctrl[13].val[6] = 0;
+
+ state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ;
+ state->Init_Ctrl[14].size = 16 ;
+ state->Init_Ctrl[14].addr[0] = 13;
+ state->Init_Ctrl[14].bit[0] = 0;
+ state->Init_Ctrl[14].val[0] = 0;
+ state->Init_Ctrl[14].addr[1] = 13;
+ state->Init_Ctrl[14].bit[1] = 1;
+ state->Init_Ctrl[14].val[1] = 0;
+ state->Init_Ctrl[14].addr[2] = 13;
+ state->Init_Ctrl[14].bit[2] = 2;
+ state->Init_Ctrl[14].val[2] = 0;
+ state->Init_Ctrl[14].addr[3] = 13;
+ state->Init_Ctrl[14].bit[3] = 3;
+ state->Init_Ctrl[14].val[3] = 0;
+ state->Init_Ctrl[14].addr[4] = 13;
+ state->Init_Ctrl[14].bit[4] = 4;
+ state->Init_Ctrl[14].val[4] = 0;
+ state->Init_Ctrl[14].addr[5] = 13;
+ state->Init_Ctrl[14].bit[5] = 5;
+ state->Init_Ctrl[14].val[5] = 0;
+ state->Init_Ctrl[14].addr[6] = 13;
+ state->Init_Ctrl[14].bit[6] = 6;
+ state->Init_Ctrl[14].val[6] = 0;
+ state->Init_Ctrl[14].addr[7] = 13;
+ state->Init_Ctrl[14].bit[7] = 7;
+ state->Init_Ctrl[14].val[7] = 0;
+ state->Init_Ctrl[14].addr[8] = 12;
+ state->Init_Ctrl[14].bit[8] = 0;
+ state->Init_Ctrl[14].val[8] = 0;
+ state->Init_Ctrl[14].addr[9] = 12;
+ state->Init_Ctrl[14].bit[9] = 1;
+ state->Init_Ctrl[14].val[9] = 0;
+ state->Init_Ctrl[14].addr[10] = 12;
+ state->Init_Ctrl[14].bit[10] = 2;
+ state->Init_Ctrl[14].val[10] = 0;
+ state->Init_Ctrl[14].addr[11] = 12;
+ state->Init_Ctrl[14].bit[11] = 3;
+ state->Init_Ctrl[14].val[11] = 0;
+ state->Init_Ctrl[14].addr[12] = 12;
+ state->Init_Ctrl[14].bit[12] = 4;
+ state->Init_Ctrl[14].val[12] = 0;
+ state->Init_Ctrl[14].addr[13] = 12;
+ state->Init_Ctrl[14].bit[13] = 5;
+ state->Init_Ctrl[14].val[13] = 1;
+ state->Init_Ctrl[14].addr[14] = 12;
+ state->Init_Ctrl[14].bit[14] = 6;
+ state->Init_Ctrl[14].val[14] = 1;
+ state->Init_Ctrl[14].addr[15] = 12;
+ state->Init_Ctrl[14].bit[15] = 7;
+ state->Init_Ctrl[14].val[15] = 0;
+
+ state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ;
+ state->Init_Ctrl[15].size = 3 ;
+ state->Init_Ctrl[15].addr[0] = 147;
+ state->Init_Ctrl[15].bit[0] = 2;
+ state->Init_Ctrl[15].val[0] = 0;
+ state->Init_Ctrl[15].addr[1] = 147;
+ state->Init_Ctrl[15].bit[1] = 3;
+ state->Init_Ctrl[15].val[1] = 1;
+ state->Init_Ctrl[15].addr[2] = 147;
+ state->Init_Ctrl[15].bit[2] = 4;
+ state->Init_Ctrl[15].val[2] = 1;
+
+ state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ;
+ state->Init_Ctrl[16].size = 2 ;
+ state->Init_Ctrl[16].addr[0] = 147;
+ state->Init_Ctrl[16].bit[0] = 0;
+ state->Init_Ctrl[16].val[0] = 0;
+ state->Init_Ctrl[16].addr[1] = 147;
+ state->Init_Ctrl[16].bit[1] = 1;
+ state->Init_Ctrl[16].val[1] = 1;
+
+ state->Init_Ctrl[17].Ctrl_Num = EN_AAF ;
+ state->Init_Ctrl[17].size = 1 ;
+ state->Init_Ctrl[17].addr[0] = 147;
+ state->Init_Ctrl[17].bit[0] = 7;
+ state->Init_Ctrl[17].val[0] = 0;
+
+ state->Init_Ctrl[18].Ctrl_Num = EN_3P ;
+ state->Init_Ctrl[18].size = 1 ;
+ state->Init_Ctrl[18].addr[0] = 147;
+ state->Init_Ctrl[18].bit[0] = 6;
+ state->Init_Ctrl[18].val[0] = 0;
+
+ state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ;
+ state->Init_Ctrl[19].size = 1 ;
+ state->Init_Ctrl[19].addr[0] = 156;
+ state->Init_Ctrl[19].bit[0] = 0;
+ state->Init_Ctrl[19].val[0] = 0;
+
+ state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ;
+ state->Init_Ctrl[20].size = 1 ;
+ state->Init_Ctrl[20].addr[0] = 147;
+ state->Init_Ctrl[20].bit[0] = 5;
+ state->Init_Ctrl[20].val[0] = 0;
+
+ state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ;
+ state->Init_Ctrl[21].size = 1 ;
+ state->Init_Ctrl[21].addr[0] = 137;
+ state->Init_Ctrl[21].bit[0] = 4;
+ state->Init_Ctrl[21].val[0] = 0;
+
+ state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ;
+ state->Init_Ctrl[22].size = 1 ;
+ state->Init_Ctrl[22].addr[0] = 137;
+ state->Init_Ctrl[22].bit[0] = 7;
+ state->Init_Ctrl[22].val[0] = 0;
+
+ state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ;
+ state->Init_Ctrl[23].size = 1 ;
+ state->Init_Ctrl[23].addr[0] = 91;
+ state->Init_Ctrl[23].bit[0] = 5;
+ state->Init_Ctrl[23].val[0] = 1;
+
+ state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ;
+ state->Init_Ctrl[24].size = 1 ;
+ state->Init_Ctrl[24].addr[0] = 43;
+ state->Init_Ctrl[24].bit[0] = 0;
+ state->Init_Ctrl[24].val[0] = 1;
+
+ state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ;
+ state->Init_Ctrl[25].size = 2 ;
+ state->Init_Ctrl[25].addr[0] = 22;
+ state->Init_Ctrl[25].bit[0] = 0;
+ state->Init_Ctrl[25].val[0] = 1;
+ state->Init_Ctrl[25].addr[1] = 22;
+ state->Init_Ctrl[25].bit[1] = 1;
+ state->Init_Ctrl[25].val[1] = 1;
+
+ state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ;
+ state->Init_Ctrl[26].size = 1 ;
+ state->Init_Ctrl[26].addr[0] = 134;
+ state->Init_Ctrl[26].bit[0] = 2;
+ state->Init_Ctrl[26].val[0] = 0;
+
+ state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ;
+ state->Init_Ctrl[27].size = 1 ;
+ state->Init_Ctrl[27].addr[0] = 137;
+ state->Init_Ctrl[27].bit[0] = 3;
+ state->Init_Ctrl[27].val[0] = 0;
+
+ state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ;
+ state->Init_Ctrl[28].size = 1 ;
+ state->Init_Ctrl[28].addr[0] = 77;
+ state->Init_Ctrl[28].bit[0] = 7;
+ state->Init_Ctrl[28].val[0] = 0;
+
+ state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ;
+ state->Init_Ctrl[29].size = 1 ;
+ state->Init_Ctrl[29].addr[0] = 166;
+ state->Init_Ctrl[29].bit[0] = 7;
+ state->Init_Ctrl[29].val[0] = 1;
+
+ state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ;
+ state->Init_Ctrl[30].size = 3 ;
+ state->Init_Ctrl[30].addr[0] = 166;
+ state->Init_Ctrl[30].bit[0] = 0;
+ state->Init_Ctrl[30].val[0] = 0;
+ state->Init_Ctrl[30].addr[1] = 166;
+ state->Init_Ctrl[30].bit[1] = 1;
+ state->Init_Ctrl[30].val[1] = 1;
+ state->Init_Ctrl[30].addr[2] = 166;
+ state->Init_Ctrl[30].bit[2] = 2;
+ state->Init_Ctrl[30].val[2] = 1;
+
+ state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ;
+ state->Init_Ctrl[31].size = 3 ;
+ state->Init_Ctrl[31].addr[0] = 166;
+ state->Init_Ctrl[31].bit[0] = 3;
+ state->Init_Ctrl[31].val[0] = 1;
+ state->Init_Ctrl[31].addr[1] = 166;
+ state->Init_Ctrl[31].bit[1] = 4;
+ state->Init_Ctrl[31].val[1] = 0;
+ state->Init_Ctrl[31].addr[2] = 166;
+ state->Init_Ctrl[31].bit[2] = 5;
+ state->Init_Ctrl[31].val[2] = 1;
+
+ state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ;
+ state->Init_Ctrl[32].size = 3 ;
+ state->Init_Ctrl[32].addr[0] = 167;
+ state->Init_Ctrl[32].bit[0] = 0;
+ state->Init_Ctrl[32].val[0] = 1;
+ state->Init_Ctrl[32].addr[1] = 167;
+ state->Init_Ctrl[32].bit[1] = 1;
+ state->Init_Ctrl[32].val[1] = 1;
+ state->Init_Ctrl[32].addr[2] = 167;
+ state->Init_Ctrl[32].bit[2] = 2;
+ state->Init_Ctrl[32].val[2] = 0;
+
+ state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ;
+ state->Init_Ctrl[33].size = 4 ;
+ state->Init_Ctrl[33].addr[0] = 168;
+ state->Init_Ctrl[33].bit[0] = 0;
+ state->Init_Ctrl[33].val[0] = 0;
+ state->Init_Ctrl[33].addr[1] = 168;
+ state->Init_Ctrl[33].bit[1] = 1;
+ state->Init_Ctrl[33].val[1] = 1;
+ state->Init_Ctrl[33].addr[2] = 168;
+ state->Init_Ctrl[33].bit[2] = 2;
+ state->Init_Ctrl[33].val[2] = 0;
+ state->Init_Ctrl[33].addr[3] = 168;
+ state->Init_Ctrl[33].bit[3] = 3;
+ state->Init_Ctrl[33].val[3] = 0;
+
+ state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ;
+ state->Init_Ctrl[34].size = 4 ;
+ state->Init_Ctrl[34].addr[0] = 168;
+ state->Init_Ctrl[34].bit[0] = 4;
+ state->Init_Ctrl[34].val[0] = 1;
+ state->Init_Ctrl[34].addr[1] = 168;
+ state->Init_Ctrl[34].bit[1] = 5;
+ state->Init_Ctrl[34].val[1] = 1;
+ state->Init_Ctrl[34].addr[2] = 168;
+ state->Init_Ctrl[34].bit[2] = 6;
+ state->Init_Ctrl[34].val[2] = 1;
+ state->Init_Ctrl[34].addr[3] = 168;
+ state->Init_Ctrl[34].bit[3] = 7;
+ state->Init_Ctrl[34].val[3] = 1;
+
+ state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ;
+ state->Init_Ctrl[35].size = 1 ;
+ state->Init_Ctrl[35].addr[0] = 135;
+ state->Init_Ctrl[35].bit[0] = 0;
+ state->Init_Ctrl[35].val[0] = 0;
+
+ state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ;
+ state->Init_Ctrl[36].size = 1 ;
+ state->Init_Ctrl[36].addr[0] = 56;
+ state->Init_Ctrl[36].bit[0] = 3;
+ state->Init_Ctrl[36].val[0] = 0;
+
+ state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ;
+ state->Init_Ctrl[37].size = 7 ;
+ state->Init_Ctrl[37].addr[0] = 59;
+ state->Init_Ctrl[37].bit[0] = 1;
+ state->Init_Ctrl[37].val[0] = 0;
+ state->Init_Ctrl[37].addr[1] = 59;
+ state->Init_Ctrl[37].bit[1] = 2;
+ state->Init_Ctrl[37].val[1] = 0;
+ state->Init_Ctrl[37].addr[2] = 59;
+ state->Init_Ctrl[37].bit[2] = 3;
+ state->Init_Ctrl[37].val[2] = 0;
+ state->Init_Ctrl[37].addr[3] = 59;
+ state->Init_Ctrl[37].bit[3] = 4;
+ state->Init_Ctrl[37].val[3] = 0;
+ state->Init_Ctrl[37].addr[4] = 59;
+ state->Init_Ctrl[37].bit[4] = 5;
+ state->Init_Ctrl[37].val[4] = 0;
+ state->Init_Ctrl[37].addr[5] = 59;
+ state->Init_Ctrl[37].bit[5] = 6;
+ state->Init_Ctrl[37].val[5] = 0;
+ state->Init_Ctrl[37].addr[6] = 59;
+ state->Init_Ctrl[37].bit[6] = 7;
+ state->Init_Ctrl[37].val[6] = 0;
+
+ state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ;
+ state->Init_Ctrl[38].size = 6 ;
+ state->Init_Ctrl[38].addr[0] = 32;
+ state->Init_Ctrl[38].bit[0] = 2;
+ state->Init_Ctrl[38].val[0] = 0;
+ state->Init_Ctrl[38].addr[1] = 32;
+ state->Init_Ctrl[38].bit[1] = 3;
+ state->Init_Ctrl[38].val[1] = 0;
+ state->Init_Ctrl[38].addr[2] = 32;
+ state->Init_Ctrl[38].bit[2] = 4;
+ state->Init_Ctrl[38].val[2] = 0;
+ state->Init_Ctrl[38].addr[3] = 32;
+ state->Init_Ctrl[38].bit[3] = 5;
+ state->Init_Ctrl[38].val[3] = 0;
+ state->Init_Ctrl[38].addr[4] = 32;
+ state->Init_Ctrl[38].bit[4] = 6;
+ state->Init_Ctrl[38].val[4] = 1;
+ state->Init_Ctrl[38].addr[5] = 32;
+ state->Init_Ctrl[38].bit[5] = 7;
+ state->Init_Ctrl[38].val[5] = 0;
+
+ state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ;
+ state->Init_Ctrl[39].size = 1 ;
+ state->Init_Ctrl[39].addr[0] = 25;
+ state->Init_Ctrl[39].bit[0] = 3;
+ state->Init_Ctrl[39].val[0] = 1;
+
+
+ state->CH_Ctrl_Num = CHCTRL_NUM ;
+
+ state->CH_Ctrl[0].Ctrl_Num = DN_POLY ;
+ state->CH_Ctrl[0].size = 2 ;
+ state->CH_Ctrl[0].addr[0] = 68;
+ state->CH_Ctrl[0].bit[0] = 6;
+ state->CH_Ctrl[0].val[0] = 1;
+ state->CH_Ctrl[0].addr[1] = 68;
+ state->CH_Ctrl[0].bit[1] = 7;
+ state->CH_Ctrl[0].val[1] = 1;
+
+ state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ;
+ state->CH_Ctrl[1].size = 2 ;
+ state->CH_Ctrl[1].addr[0] = 70;
+ state->CH_Ctrl[1].bit[0] = 6;
+ state->CH_Ctrl[1].val[0] = 1;
+ state->CH_Ctrl[1].addr[1] = 70;
+ state->CH_Ctrl[1].bit[1] = 7;
+ state->CH_Ctrl[1].val[1] = 0;
+
+ state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ;
+ state->CH_Ctrl[2].size = 9 ;
+ state->CH_Ctrl[2].addr[0] = 69;
+ state->CH_Ctrl[2].bit[0] = 5;
+ state->CH_Ctrl[2].val[0] = 0;
+ state->CH_Ctrl[2].addr[1] = 69;
+ state->CH_Ctrl[2].bit[1] = 6;
+ state->CH_Ctrl[2].val[1] = 0;
+ state->CH_Ctrl[2].addr[2] = 69;
+ state->CH_Ctrl[2].bit[2] = 7;
+ state->CH_Ctrl[2].val[2] = 0;
+ state->CH_Ctrl[2].addr[3] = 68;
+ state->CH_Ctrl[2].bit[3] = 0;
+ state->CH_Ctrl[2].val[3] = 0;
+ state->CH_Ctrl[2].addr[4] = 68;
+ state->CH_Ctrl[2].bit[4] = 1;
+ state->CH_Ctrl[2].val[4] = 0;
+ state->CH_Ctrl[2].addr[5] = 68;
+ state->CH_Ctrl[2].bit[5] = 2;
+ state->CH_Ctrl[2].val[5] = 0;
+ state->CH_Ctrl[2].addr[6] = 68;
+ state->CH_Ctrl[2].bit[6] = 3;
+ state->CH_Ctrl[2].val[6] = 0;
+ state->CH_Ctrl[2].addr[7] = 68;
+ state->CH_Ctrl[2].bit[7] = 4;
+ state->CH_Ctrl[2].val[7] = 0;
+ state->CH_Ctrl[2].addr[8] = 68;
+ state->CH_Ctrl[2].bit[8] = 5;
+ state->CH_Ctrl[2].val[8] = 0;
+
+ state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ;
+ state->CH_Ctrl[3].size = 1 ;
+ state->CH_Ctrl[3].addr[0] = 70;
+ state->CH_Ctrl[3].bit[0] = 5;
+ state->CH_Ctrl[3].val[0] = 0;
+
+ state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ;
+ state->CH_Ctrl[4].size = 3 ;
+ state->CH_Ctrl[4].addr[0] = 73;
+ state->CH_Ctrl[4].bit[0] = 4;
+ state->CH_Ctrl[4].val[0] = 0;
+ state->CH_Ctrl[4].addr[1] = 73;
+ state->CH_Ctrl[4].bit[1] = 5;
+ state->CH_Ctrl[4].val[1] = 1;
+ state->CH_Ctrl[4].addr[2] = 73;
+ state->CH_Ctrl[4].bit[2] = 6;
+ state->CH_Ctrl[4].val[2] = 0;
+
+ state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ;
+ state->CH_Ctrl[5].size = 4 ;
+ state->CH_Ctrl[5].addr[0] = 70;
+ state->CH_Ctrl[5].bit[0] = 0;
+ state->CH_Ctrl[5].val[0] = 0;
+ state->CH_Ctrl[5].addr[1] = 70;
+ state->CH_Ctrl[5].bit[1] = 1;
+ state->CH_Ctrl[5].val[1] = 0;
+ state->CH_Ctrl[5].addr[2] = 70;
+ state->CH_Ctrl[5].bit[2] = 2;
+ state->CH_Ctrl[5].val[2] = 0;
+ state->CH_Ctrl[5].addr[3] = 70;
+ state->CH_Ctrl[5].bit[3] = 3;
+ state->CH_Ctrl[5].val[3] = 0;
+
+ state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ;
+ state->CH_Ctrl[6].size = 1 ;
+ state->CH_Ctrl[6].addr[0] = 70;
+ state->CH_Ctrl[6].bit[0] = 4;
+ state->CH_Ctrl[6].val[0] = 1;
+
+ state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ;
+ state->CH_Ctrl[7].size = 1 ;
+ state->CH_Ctrl[7].addr[0] = 111;
+ state->CH_Ctrl[7].bit[0] = 4;
+ state->CH_Ctrl[7].val[0] = 0;
+
+ state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ;
+ state->CH_Ctrl[8].size = 1 ;
+ state->CH_Ctrl[8].addr[0] = 111;
+ state->CH_Ctrl[8].bit[0] = 7;
+ state->CH_Ctrl[8].val[0] = 1;
+
+ state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ;
+ state->CH_Ctrl[9].size = 1 ;
+ state->CH_Ctrl[9].addr[0] = 111;
+ state->CH_Ctrl[9].bit[0] = 6;
+ state->CH_Ctrl[9].val[0] = 1;
+
+ state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ;
+ state->CH_Ctrl[10].size = 1 ;
+ state->CH_Ctrl[10].addr[0] = 111;
+ state->CH_Ctrl[10].bit[0] = 5;
+ state->CH_Ctrl[10].val[0] = 0;
+
+ state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ;
+ state->CH_Ctrl[11].size = 2 ;
+ state->CH_Ctrl[11].addr[0] = 110;
+ state->CH_Ctrl[11].bit[0] = 0;
+ state->CH_Ctrl[11].val[0] = 1;
+ state->CH_Ctrl[11].addr[1] = 110;
+ state->CH_Ctrl[11].bit[1] = 1;
+ state->CH_Ctrl[11].val[1] = 0;
+
+ state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ;
+ state->CH_Ctrl[12].size = 3 ;
+ state->CH_Ctrl[12].addr[0] = 69;
+ state->CH_Ctrl[12].bit[0] = 2;
+ state->CH_Ctrl[12].val[0] = 0;
+ state->CH_Ctrl[12].addr[1] = 69;
+ state->CH_Ctrl[12].bit[1] = 3;
+ state->CH_Ctrl[12].val[1] = 0;
+ state->CH_Ctrl[12].addr[2] = 69;
+ state->CH_Ctrl[12].bit[2] = 4;
+ state->CH_Ctrl[12].val[2] = 0;
+
+ state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ;
+ state->CH_Ctrl[13].size = 6 ;
+ state->CH_Ctrl[13].addr[0] = 110;
+ state->CH_Ctrl[13].bit[0] = 2;
+ state->CH_Ctrl[13].val[0] = 0;
+ state->CH_Ctrl[13].addr[1] = 110;
+ state->CH_Ctrl[13].bit[1] = 3;
+ state->CH_Ctrl[13].val[1] = 0;
+ state->CH_Ctrl[13].addr[2] = 110;
+ state->CH_Ctrl[13].bit[2] = 4;
+ state->CH_Ctrl[13].val[2] = 0;
+ state->CH_Ctrl[13].addr[3] = 110;
+ state->CH_Ctrl[13].bit[3] = 5;
+ state->CH_Ctrl[13].val[3] = 0;
+ state->CH_Ctrl[13].addr[4] = 110;
+ state->CH_Ctrl[13].bit[4] = 6;
+ state->CH_Ctrl[13].val[4] = 0;
+ state->CH_Ctrl[13].addr[5] = 110;
+ state->CH_Ctrl[13].bit[5] = 7;
+ state->CH_Ctrl[13].val[5] = 1;
+
+ state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ;
+ state->CH_Ctrl[14].size = 7 ;
+ state->CH_Ctrl[14].addr[0] = 14;
+ state->CH_Ctrl[14].bit[0] = 0;
+ state->CH_Ctrl[14].val[0] = 0;
+ state->CH_Ctrl[14].addr[1] = 14;
+ state->CH_Ctrl[14].bit[1] = 1;
+ state->CH_Ctrl[14].val[1] = 0;
+ state->CH_Ctrl[14].addr[2] = 14;
+ state->CH_Ctrl[14].bit[2] = 2;
+ state->CH_Ctrl[14].val[2] = 0;
+ state->CH_Ctrl[14].addr[3] = 14;
+ state->CH_Ctrl[14].bit[3] = 3;
+ state->CH_Ctrl[14].val[3] = 0;
+ state->CH_Ctrl[14].addr[4] = 14;
+ state->CH_Ctrl[14].bit[4] = 4;
+ state->CH_Ctrl[14].val[4] = 0;
+ state->CH_Ctrl[14].addr[5] = 14;
+ state->CH_Ctrl[14].bit[5] = 5;
+ state->CH_Ctrl[14].val[5] = 0;
+ state->CH_Ctrl[14].addr[6] = 14;
+ state->CH_Ctrl[14].bit[6] = 6;
+ state->CH_Ctrl[14].val[6] = 0;
+
+ state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ;
+ state->CH_Ctrl[15].size = 18 ;
+ state->CH_Ctrl[15].addr[0] = 17;
+ state->CH_Ctrl[15].bit[0] = 6;
+ state->CH_Ctrl[15].val[0] = 0;
+ state->CH_Ctrl[15].addr[1] = 17;
+ state->CH_Ctrl[15].bit[1] = 7;
+ state->CH_Ctrl[15].val[1] = 0;
+ state->CH_Ctrl[15].addr[2] = 16;
+ state->CH_Ctrl[15].bit[2] = 0;
+ state->CH_Ctrl[15].val[2] = 0;
+ state->CH_Ctrl[15].addr[3] = 16;
+ state->CH_Ctrl[15].bit[3] = 1;
+ state->CH_Ctrl[15].val[3] = 0;
+ state->CH_Ctrl[15].addr[4] = 16;
+ state->CH_Ctrl[15].bit[4] = 2;
+ state->CH_Ctrl[15].val[4] = 0;
+ state->CH_Ctrl[15].addr[5] = 16;
+ state->CH_Ctrl[15].bit[5] = 3;
+ state->CH_Ctrl[15].val[5] = 0;
+ state->CH_Ctrl[15].addr[6] = 16;
+ state->CH_Ctrl[15].bit[6] = 4;
+ state->CH_Ctrl[15].val[6] = 0;
+ state->CH_Ctrl[15].addr[7] = 16;
+ state->CH_Ctrl[15].bit[7] = 5;
+ state->CH_Ctrl[15].val[7] = 0;
+ state->CH_Ctrl[15].addr[8] = 16;
+ state->CH_Ctrl[15].bit[8] = 6;
+ state->CH_Ctrl[15].val[8] = 0;
+ state->CH_Ctrl[15].addr[9] = 16;
+ state->CH_Ctrl[15].bit[9] = 7;
+ state->CH_Ctrl[15].val[9] = 0;
+ state->CH_Ctrl[15].addr[10] = 15;
+ state->CH_Ctrl[15].bit[10] = 0;
+ state->CH_Ctrl[15].val[10] = 0;
+ state->CH_Ctrl[15].addr[11] = 15;
+ state->CH_Ctrl[15].bit[11] = 1;
+ state->CH_Ctrl[15].val[11] = 0;
+ state->CH_Ctrl[15].addr[12] = 15;
+ state->CH_Ctrl[15].bit[12] = 2;
+ state->CH_Ctrl[15].val[12] = 0;
+ state->CH_Ctrl[15].addr[13] = 15;
+ state->CH_Ctrl[15].bit[13] = 3;
+ state->CH_Ctrl[15].val[13] = 0;
+ state->CH_Ctrl[15].addr[14] = 15;
+ state->CH_Ctrl[15].bit[14] = 4;
+ state->CH_Ctrl[15].val[14] = 0;
+ state->CH_Ctrl[15].addr[15] = 15;
+ state->CH_Ctrl[15].bit[15] = 5;
+ state->CH_Ctrl[15].val[15] = 0;
+ state->CH_Ctrl[15].addr[16] = 15;
+ state->CH_Ctrl[15].bit[16] = 6;
+ state->CH_Ctrl[15].val[16] = 1;
+ state->CH_Ctrl[15].addr[17] = 15;
+ state->CH_Ctrl[15].bit[17] = 7;
+ state->CH_Ctrl[15].val[17] = 1;
+
+ state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ;
+ state->CH_Ctrl[16].size = 5 ;
+ state->CH_Ctrl[16].addr[0] = 112;
+ state->CH_Ctrl[16].bit[0] = 0;
+ state->CH_Ctrl[16].val[0] = 0;
+ state->CH_Ctrl[16].addr[1] = 112;
+ state->CH_Ctrl[16].bit[1] = 1;
+ state->CH_Ctrl[16].val[1] = 0;
+ state->CH_Ctrl[16].addr[2] = 112;
+ state->CH_Ctrl[16].bit[2] = 2;
+ state->CH_Ctrl[16].val[2] = 0;
+ state->CH_Ctrl[16].addr[3] = 112;
+ state->CH_Ctrl[16].bit[3] = 3;
+ state->CH_Ctrl[16].val[3] = 0;
+ state->CH_Ctrl[16].addr[4] = 112;
+ state->CH_Ctrl[16].bit[4] = 4;
+ state->CH_Ctrl[16].val[4] = 1;
+
+ state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ;
+ state->CH_Ctrl[17].size = 1 ;
+ state->CH_Ctrl[17].addr[0] = 14;
+ state->CH_Ctrl[17].bit[0] = 7;
+ state->CH_Ctrl[17].val[0] = 0;
+
+ state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ;
+ state->CH_Ctrl[18].size = 4 ;
+ state->CH_Ctrl[18].addr[0] = 107;
+ state->CH_Ctrl[18].bit[0] = 3;
+ state->CH_Ctrl[18].val[0] = 0;
+ state->CH_Ctrl[18].addr[1] = 107;
+ state->CH_Ctrl[18].bit[1] = 4;
+ state->CH_Ctrl[18].val[1] = 0;
+ state->CH_Ctrl[18].addr[2] = 107;
+ state->CH_Ctrl[18].bit[2] = 5;
+ state->CH_Ctrl[18].val[2] = 0;
+ state->CH_Ctrl[18].addr[3] = 107;
+ state->CH_Ctrl[18].bit[3] = 6;
+ state->CH_Ctrl[18].val[3] = 0;
+
+ state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ;
+ state->CH_Ctrl[19].size = 3 ;
+ state->CH_Ctrl[19].addr[0] = 107;
+ state->CH_Ctrl[19].bit[0] = 7;
+ state->CH_Ctrl[19].val[0] = 1;
+ state->CH_Ctrl[19].addr[1] = 106;
+ state->CH_Ctrl[19].bit[1] = 0;
+ state->CH_Ctrl[19].val[1] = 1;
+ state->CH_Ctrl[19].addr[2] = 106;
+ state->CH_Ctrl[19].bit[2] = 1;
+ state->CH_Ctrl[19].val[2] = 1;
+
+ state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ;
+ state->CH_Ctrl[20].size = 11 ;
+ state->CH_Ctrl[20].addr[0] = 109;
+ state->CH_Ctrl[20].bit[0] = 2;
+ state->CH_Ctrl[20].val[0] = 0;
+ state->CH_Ctrl[20].addr[1] = 109;
+ state->CH_Ctrl[20].bit[1] = 3;
+ state->CH_Ctrl[20].val[1] = 0;
+ state->CH_Ctrl[20].addr[2] = 109;
+ state->CH_Ctrl[20].bit[2] = 4;
+ state->CH_Ctrl[20].val[2] = 0;
+ state->CH_Ctrl[20].addr[3] = 109;
+ state->CH_Ctrl[20].bit[3] = 5;
+ state->CH_Ctrl[20].val[3] = 0;
+ state->CH_Ctrl[20].addr[4] = 109;
+ state->CH_Ctrl[20].bit[4] = 6;
+ state->CH_Ctrl[20].val[4] = 0;
+ state->CH_Ctrl[20].addr[5] = 109;
+ state->CH_Ctrl[20].bit[5] = 7;
+ state->CH_Ctrl[20].val[5] = 0;
+ state->CH_Ctrl[20].addr[6] = 108;
+ state->CH_Ctrl[20].bit[6] = 0;
+ state->CH_Ctrl[20].val[6] = 0;
+ state->CH_Ctrl[20].addr[7] = 108;
+ state->CH_Ctrl[20].bit[7] = 1;
+ state->CH_Ctrl[20].val[7] = 0;
+ state->CH_Ctrl[20].addr[8] = 108;
+ state->CH_Ctrl[20].bit[8] = 2;
+ state->CH_Ctrl[20].val[8] = 1;
+ state->CH_Ctrl[20].addr[9] = 108;
+ state->CH_Ctrl[20].bit[9] = 3;
+ state->CH_Ctrl[20].val[9] = 1;
+ state->CH_Ctrl[20].addr[10] = 108;
+ state->CH_Ctrl[20].bit[10] = 4;
+ state->CH_Ctrl[20].val[10] = 1;
+
+ state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ;
+ state->CH_Ctrl[21].size = 6 ;
+ state->CH_Ctrl[21].addr[0] = 106;
+ state->CH_Ctrl[21].bit[0] = 2;
+ state->CH_Ctrl[21].val[0] = 0;
+ state->CH_Ctrl[21].addr[1] = 106;
+ state->CH_Ctrl[21].bit[1] = 3;
+ state->CH_Ctrl[21].val[1] = 0;
+ state->CH_Ctrl[21].addr[2] = 106;
+ state->CH_Ctrl[21].bit[2] = 4;
+ state->CH_Ctrl[21].val[2] = 0;
+ state->CH_Ctrl[21].addr[3] = 106;
+ state->CH_Ctrl[21].bit[3] = 5;
+ state->CH_Ctrl[21].val[3] = 0;
+ state->CH_Ctrl[21].addr[4] = 106;
+ state->CH_Ctrl[21].bit[4] = 6;
+ state->CH_Ctrl[21].val[4] = 0;
+ state->CH_Ctrl[21].addr[5] = 106;
+ state->CH_Ctrl[21].bit[5] = 7;
+ state->CH_Ctrl[21].val[5] = 1;
+
+ state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ;
+ state->CH_Ctrl[22].size = 1 ;
+ state->CH_Ctrl[22].addr[0] = 138;
+ state->CH_Ctrl[22].bit[0] = 4;
+ state->CH_Ctrl[22].val[0] = 1;
+
+ state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ;
+ state->CH_Ctrl[23].size = 1 ;
+ state->CH_Ctrl[23].addr[0] = 17;
+ state->CH_Ctrl[23].bit[0] = 5;
+ state->CH_Ctrl[23].val[0] = 0;
+
+ state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ;
+ state->CH_Ctrl[24].size = 1 ;
+ state->CH_Ctrl[24].addr[0] = 111;
+ state->CH_Ctrl[24].bit[0] = 3;
+ state->CH_Ctrl[24].val[0] = 0;
+
+ state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ;
+ state->CH_Ctrl[25].size = 1 ;
+ state->CH_Ctrl[25].addr[0] = 112;
+ state->CH_Ctrl[25].bit[0] = 7;
+ state->CH_Ctrl[25].val[0] = 0;
+
+ state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ;
+ state->CH_Ctrl[26].size = 1 ;
+ state->CH_Ctrl[26].addr[0] = 136;
+ state->CH_Ctrl[26].bit[0] = 7;
+ state->CH_Ctrl[26].val[0] = 0;
+
+ state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ;
+ state->CH_Ctrl[27].size = 1 ;
+ state->CH_Ctrl[27].addr[0] = 149;
+ state->CH_Ctrl[27].bit[0] = 7;
+ state->CH_Ctrl[27].val[0] = 0;
+
+ state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ;
+ state->CH_Ctrl[28].size = 1 ;
+ state->CH_Ctrl[28].addr[0] = 149;
+ state->CH_Ctrl[28].bit[0] = 6;
+ state->CH_Ctrl[28].val[0] = 0;
+
+ state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ;
+ state->CH_Ctrl[29].size = 1 ;
+ state->CH_Ctrl[29].addr[0] = 149;
+ state->CH_Ctrl[29].bit[0] = 5;
+ state->CH_Ctrl[29].val[0] = 1;
+
+ state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ;
+ state->CH_Ctrl[30].size = 1 ;
+ state->CH_Ctrl[30].addr[0] = 149;
+ state->CH_Ctrl[30].bit[0] = 4;
+ state->CH_Ctrl[30].val[0] = 1;
+
+ state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ;
+ state->CH_Ctrl[31].size = 1 ;
+ state->CH_Ctrl[31].addr[0] = 149;
+ state->CH_Ctrl[31].bit[0] = 3;
+ state->CH_Ctrl[31].val[0] = 0;
+
+ state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ;
+ state->CH_Ctrl[32].size = 1 ;
+ state->CH_Ctrl[32].addr[0] = 93;
+ state->CH_Ctrl[32].bit[0] = 1;
+ state->CH_Ctrl[32].val[0] = 0;
+
+ state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ;
+ state->CH_Ctrl[33].size = 1 ;
+ state->CH_Ctrl[33].addr[0] = 93;
+ state->CH_Ctrl[33].bit[0] = 0;
+ state->CH_Ctrl[33].val[0] = 0;
+
+ state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ;
+ state->CH_Ctrl[34].size = 6 ;
+ state->CH_Ctrl[34].addr[0] = 92;
+ state->CH_Ctrl[34].bit[0] = 2;
+ state->CH_Ctrl[34].val[0] = 0;
+ state->CH_Ctrl[34].addr[1] = 92;
+ state->CH_Ctrl[34].bit[1] = 3;
+ state->CH_Ctrl[34].val[1] = 0;
+ state->CH_Ctrl[34].addr[2] = 92;
+ state->CH_Ctrl[34].bit[2] = 4;
+ state->CH_Ctrl[34].val[2] = 0;
+ state->CH_Ctrl[34].addr[3] = 92;
+ state->CH_Ctrl[34].bit[3] = 5;
+ state->CH_Ctrl[34].val[3] = 0;
+ state->CH_Ctrl[34].addr[4] = 92;
+ state->CH_Ctrl[34].bit[4] = 6;
+ state->CH_Ctrl[34].val[4] = 0;
+ state->CH_Ctrl[34].addr[5] = 92;
+ state->CH_Ctrl[34].bit[5] = 7;
+ state->CH_Ctrl[34].val[5] = 0;
+
+ state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ;
+ state->CH_Ctrl[35].size = 6 ;
+ state->CH_Ctrl[35].addr[0] = 93;
+ state->CH_Ctrl[35].bit[0] = 2;
+ state->CH_Ctrl[35].val[0] = 0;
+ state->CH_Ctrl[35].addr[1] = 93;
+ state->CH_Ctrl[35].bit[1] = 3;
+ state->CH_Ctrl[35].val[1] = 0;
+ state->CH_Ctrl[35].addr[2] = 93;
+ state->CH_Ctrl[35].bit[2] = 4;
+ state->CH_Ctrl[35].val[2] = 0;
+ state->CH_Ctrl[35].addr[3] = 93;
+ state->CH_Ctrl[35].bit[3] = 5;
+ state->CH_Ctrl[35].val[3] = 0;
+ state->CH_Ctrl[35].addr[4] = 93;
+ state->CH_Ctrl[35].bit[4] = 6;
+ state->CH_Ctrl[35].val[4] = 0;
+ state->CH_Ctrl[35].addr[5] = 93;
+ state->CH_Ctrl[35].bit[5] = 7;
+ state->CH_Ctrl[35].val[5] = 0;
+
+#ifdef _MXL_PRODUCTION
+ state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ;
+ state->CH_Ctrl[36].size = 1 ;
+ state->CH_Ctrl[36].addr[0] = 109;
+ state->CH_Ctrl[36].bit[0] = 1;
+ state->CH_Ctrl[36].val[0] = 1;
+
+ state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ;
+ state->CH_Ctrl[37].size = 2 ;
+ state->CH_Ctrl[37].addr[0] = 112;
+ state->CH_Ctrl[37].bit[0] = 5;
+ state->CH_Ctrl[37].val[0] = 0;
+ state->CH_Ctrl[37].addr[1] = 112;
+ state->CH_Ctrl[37].bit[1] = 6;
+ state->CH_Ctrl[37].val[1] = 0;
+
+ state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ;
+ state->CH_Ctrl[38].size = 1 ;
+ state->CH_Ctrl[38].addr[0] = 65;
+ state->CH_Ctrl[38].bit[0] = 1;
+ state->CH_Ctrl[38].val[0] = 0;
+#endif
+
+ return 0 ;
+}
+
+static void InitTunerControls(struct dvb_frontend *fe)
+{
+ MXL5005_RegisterInit(fe);
+ MXL5005_ControlInit(fe);
+#ifdef _MXL_INTERNAL
+ MXL5005_MXLControlInit(fe);
+#endif
+}
+
+static u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
+ u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */
+ u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */
+ u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */
+ u32 IF_out, /* Desired IF Out Frequency */
+ u32 Fxtal, /* XTAL Frequency */
+ u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */
+ u16 TOP, /* 0: Dual AGC; Value: take over point */
+ u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */
+ u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */
+ u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */
+ u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */
+ u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */
+
+ /* Modulation Type; */
+ /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */
+ u8 Mod_Type,
+
+ /* Tracking Filter */
+ /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */
+ u8 TF_Type
+ )
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 status = 0;
+
+ state->Mode = Mode;
+ state->IF_Mode = IF_mode;
+ state->Chan_Bandwidth = Bandwidth;
+ state->IF_OUT = IF_out;
+ state->Fxtal = Fxtal;
+ state->AGC_Mode = AGC_Mode;
+ state->TOP = TOP;
+ state->IF_OUT_LOAD = IF_OUT_LOAD;
+ state->CLOCK_OUT = CLOCK_OUT;
+ state->DIV_OUT = DIV_OUT;
+ state->CAPSELECT = CAPSELECT;
+ state->EN_RSSI = EN_RSSI;
+ state->Mod_Type = Mod_Type;
+ state->TF_Type = TF_Type;
+
+ /* Initialize all the controls and registers */
+ InitTunerControls(fe);
+
+ /* Synthesizer LO frequency calculation */
+ MXL_SynthIFLO_Calc(fe);
+
+ return status;
+}
+
+static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ if (state->Mode == 1) /* Digital Mode */
+ state->IF_LO = state->IF_OUT;
+ else /* Analog Mode */ {
+ if (state->IF_Mode == 0) /* Analog Zero IF mode */
+ state->IF_LO = state->IF_OUT + 400000;
+ else /* Analog Low IF mode */
+ state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2;
+ }
+}
+
+static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+
+ if (state->Mode == 1) /* Digital Mode */ {
+ /* remove 20.48MHz setting for 2.6.10 */
+ state->RF_LO = state->RF_IN;
+ /* change for 2.6.6 */
+ state->TG_LO = state->RF_IN - 750000;
+ } else /* Analog Mode */ {
+ if (state->IF_Mode == 0) /* Analog Zero IF mode */ {
+ state->RF_LO = state->RF_IN - 400000;
+ state->TG_LO = state->RF_IN - 1750000;
+ } else /* Analog Low IF mode */ {
+ state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2;
+ state->TG_LO = state->RF_IN -
+ state->Chan_Bandwidth + 500000;
+ }
+ }
+}
+
+static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe)
+{
+ u16 status = 0;
+
+ status += MXL_ControlWrite(fe, OVERRIDE_1, 1);
+ status += MXL_ControlWrite(fe, OVERRIDE_2, 1);
+ status += MXL_ControlWrite(fe, OVERRIDE_3, 1);
+ status += MXL_ControlWrite(fe, OVERRIDE_4, 1);
+
+ return status;
+}
+
+static u16 MXL_BlockInit(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 status = 0;
+
+ status += MXL_OverwriteICDefault(fe);
+
+ /* Downconverter Control Dig Ana */
+ status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0);
+
+ /* Filter Control Dig Ana */
+ status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1);
+ status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2);
+ status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0);
+ status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1);
+ status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0);
+
+ /* Initialize Low-Pass Filter */
+ if (state->Mode) { /* Digital Mode */
+ switch (state->Chan_Bandwidth) {
+ case 8000000:
+ status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0);
+ break;
+ case 7000000:
+ status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2);
+ break;
+ case 6000000:
+ status += MXL_ControlWrite(fe,
+ BB_DLPF_BANDSEL, 3);
+ break;
+ }
+ } else { /* Analog Mode */
+ switch (state->Chan_Bandwidth) {
+ case 8000000: /* Low Zero */
+ status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+ (state->IF_Mode ? 0 : 3));
+ break;
+ case 7000000:
+ status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+ (state->IF_Mode ? 1 : 4));
+ break;
+ case 6000000:
+ status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT,
+ (state->IF_Mode ? 2 : 5));
+ break;
+ }
+ }
+
+ /* Charge Pump Control Dig Ana */
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8);
+ status += MXL_ControlWrite(fe,
+ RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1);
+ status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0);
+
+ /* AGC TOP Control */
+ if (state->AGC_Mode == 0) /* Dual AGC */ {
+ status += MXL_ControlWrite(fe, AGC_IF, 15);
+ status += MXL_ControlWrite(fe, AGC_RF, 15);
+ } else /* Single AGC Mode Dig Ana */
+ status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12);
+
+ if (state->TOP == 55) /* TOP == 5.5 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x0);
+
+ if (state->TOP == 72) /* TOP == 7.2 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x1);
+
+ if (state->TOP == 92) /* TOP == 9.2 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x2);
+
+ if (state->TOP == 110) /* TOP == 11.0 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x3);
+
+ if (state->TOP == 129) /* TOP == 12.9 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x4);
+
+ if (state->TOP == 147) /* TOP == 14.7 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x5);
+
+ if (state->TOP == 168) /* TOP == 16.8 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x6);
+
+ if (state->TOP == 194) /* TOP == 19.4 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x7);
+
+ if (state->TOP == 212) /* TOP == 21.2 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0x9);
+
+ if (state->TOP == 232) /* TOP == 23.2 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0xA);
+
+ if (state->TOP == 252) /* TOP == 25.2 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0xB);
+
+ if (state->TOP == 271) /* TOP == 27.1 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0xC);
+
+ if (state->TOP == 292) /* TOP == 29.2 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0xD);
+
+ if (state->TOP == 317) /* TOP == 31.7 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0xE);
+
+ if (state->TOP == 349) /* TOP == 34.9 */
+ status += MXL_ControlWrite(fe, AGC_IF, 0xF);
+
+ /* IF Synthesizer Control */
+ status += MXL_IFSynthInit(fe);
+
+ /* IF UpConverter Control */
+ if (state->IF_OUT_LOAD == 200) {
+ status += MXL_ControlWrite(fe, DRV_RES_SEL, 6);
+ status += MXL_ControlWrite(fe, I_DRIVER, 2);
+ }
+ if (state->IF_OUT_LOAD == 300) {
+ status += MXL_ControlWrite(fe, DRV_RES_SEL, 4);
+ status += MXL_ControlWrite(fe, I_DRIVER, 1);
+ }
+
+ /* Anti-Alias Filtering Control
+ * initialise Anti-Aliasing Filter
+ */
+ if (state->Mode) { /* Digital Mode */
+ if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) {
+ status += MXL_ControlWrite(fe, EN_AAF, 1);
+ status += MXL_ControlWrite(fe, EN_3P, 1);
+ status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+ status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+ }
+ if ((state->IF_OUT == 36125000UL) ||
+ (state->IF_OUT == 36150000UL)) {
+ status += MXL_ControlWrite(fe, EN_AAF, 1);
+ status += MXL_ControlWrite(fe, EN_3P, 1);
+ status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+ status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
+ }
+ if (state->IF_OUT > 36150000UL) {
+ status += MXL_ControlWrite(fe, EN_AAF, 0);
+ status += MXL_ControlWrite(fe, EN_3P, 1);
+ status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+ status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1);
+ }
+ } else { /* Analog Mode */
+ if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) {
+ status += MXL_ControlWrite(fe, EN_AAF, 1);
+ status += MXL_ControlWrite(fe, EN_3P, 1);
+ status += MXL_ControlWrite(fe, EN_AUX_3P, 1);
+ status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+ }
+ if (state->IF_OUT > 5000000UL) {
+ status += MXL_ControlWrite(fe, EN_AAF, 0);
+ status += MXL_ControlWrite(fe, EN_3P, 0);
+ status += MXL_ControlWrite(fe, EN_AUX_3P, 0);
+ status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0);
+ }
+ }
+
+ /* Demod Clock Out */
+ if (state->CLOCK_OUT)
+ status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1);
+ else
+ status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0);
+
+ if (state->DIV_OUT == 1)
+ status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1);
+ if (state->DIV_OUT == 0)
+ status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0);
+
+ /* Crystal Control */
+ if (state->CAPSELECT)
+ status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1);
+ else
+ status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0);
+
+ if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
+ status += MXL_ControlWrite(fe, IF_SEL_DBL, 1);
+ if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
+ status += MXL_ControlWrite(fe, IF_SEL_DBL, 0);
+
+ if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
+ status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3);
+ if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL)
+ status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0);
+
+ /* Misc Controls */
+ if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */
+ status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0);
+ else
+ status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1);
+
+ /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */
+
+ /* Set TG_R_DIV */
+ status += MXL_ControlWrite(fe, TG_R_DIV,
+ MXL_Ceiling(state->Fxtal, 1000000));
+
+ /* Apply Default value to BB_INITSTATE_DLPF_TUNE */
+
+ /* RSSI Control */
+ if (state->EN_RSSI) {
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+ /* RSSI reference point */
+ status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+ /* TOP point */
+ status += MXL_ControlWrite(fe, RFA_FLR, 0);
+ status += MXL_ControlWrite(fe, RFA_CEIL, 12);
+ }
+
+ /* Modulation type bit settings
+ * Override the control values preset
+ */
+ if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ {
+ state->AGC_Mode = 1; /* Single AGC Mode */
+
+ /* Enable RSSI */
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+ /* RSSI reference point */
+ status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+ /* TOP point */
+ status += MXL_ControlWrite(fe, RFA_FLR, 2);
+ status += MXL_ControlWrite(fe, RFA_CEIL, 13);
+ if (state->IF_OUT <= 6280000UL) /* Low IF */
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+ else /* High IF */
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+
+ }
+ if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ {
+ state->AGC_Mode = 1; /* Single AGC Mode */
+
+ /* Enable RSSI */
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+ /* RSSI reference point */
+ status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1);
+
+ /* TOP point */
+ status += MXL_ControlWrite(fe, RFA_FLR, 2);
+ status += MXL_ControlWrite(fe, RFA_CEIL, 13);
+ status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1);
+ /* Low Zero */
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
+
+ if (state->IF_OUT <= 6280000UL) /* Low IF */
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+ else /* High IF */
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+ }
+ if (state->Mod_Type == MXL_QAM) /* QAM Mode */ {
+ state->Mode = MXL_DIGITAL_MODE;
+
+ /* state->AGC_Mode = 1; */ /* Single AGC Mode */
+
+ /* Disable RSSI */ /* change here for v2.6.5 */
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+ /* RSSI reference point */
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+ /* change here for v2.6.5 */
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+
+ if (state->IF_OUT <= 6280000UL) /* Low IF */
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
+ else /* High IF */
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
+
+ }
+ if (state->Mod_Type == MXL_ANALOG_CABLE) {
+ /* Analog Cable Mode */
+ /* state->Mode = MXL_DIGITAL_MODE; */
+
+ state->AGC_Mode = 1; /* Single AGC Mode */
+
+ /* Disable RSSI */
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+ /* change for 2.6.3 */
+ status += MXL_ControlWrite(fe, AGC_IF, 1);
+ status += MXL_ControlWrite(fe, AGC_RF, 15);
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+ }
+
+ if (state->Mod_Type == MXL_ANALOG_OTA) {
+ /* Analog OTA Terrestrial mode add for 2.6.7 */
+ /* state->Mode = MXL_ANALOG_MODE; */
+
+ /* Enable RSSI */
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+ /* RSSI reference point */
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+ status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
+ }
+
+ /* RSSI disable */
+ if (state->EN_RSSI == 0) {
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+ }
+
+ return status;
+}
+
+static u16 MXL_IFSynthInit(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 status = 0 ;
+ u32 Fref = 0 ;
+ u32 Kdbl, intModVal ;
+ u32 fracModVal ;
+ Kdbl = 2 ;
+
+ if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL)
+ Kdbl = 2 ;
+ if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL)
+ Kdbl = 1 ;
+
+ /* IF Synthesizer Control */
+ if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ {
+ if (state->IF_LO == 41000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 328000000UL ;
+ }
+ if (state->IF_LO == 47000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 376000000UL ;
+ }
+ if (state->IF_LO == 54000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 324000000UL ;
+ }
+ if (state->IF_LO == 60000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 360000000UL ;
+ }
+ if (state->IF_LO == 39250000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 314000000UL ;
+ }
+ if (state->IF_LO == 39650000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 317200000UL ;
+ }
+ if (state->IF_LO == 40150000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 321200000UL ;
+ }
+ if (state->IF_LO == 40650000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 325200000UL ;
+ }
+ }
+
+ if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) {
+ if (state->IF_LO == 57000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 342000000UL ;
+ }
+ if (state->IF_LO == 44000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 352000000UL ;
+ }
+ if (state->IF_LO == 43750000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 350000000UL ;
+ }
+ if (state->IF_LO == 36650000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 366500000UL ;
+ }
+ if (state->IF_LO == 36150000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 361500000UL ;
+ }
+ if (state->IF_LO == 36000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 360000000UL ;
+ }
+ if (state->IF_LO == 35250000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 352500000UL ;
+ }
+ if (state->IF_LO == 34750000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 347500000UL ;
+ }
+ if (state->IF_LO == 6280000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 376800000UL ;
+ }
+ if (state->IF_LO == 5000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 360000000UL ;
+ }
+ if (state->IF_LO == 4500000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 360000000UL ;
+ }
+ if (state->IF_LO == 4570000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 365600000UL ;
+ }
+ if (state->IF_LO == 4000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 360000000UL ;
+ }
+ if (state->IF_LO == 57400000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 344400000UL ;
+ }
+ if (state->IF_LO == 44400000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 355200000UL ;
+ }
+ if (state->IF_LO == 44150000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 353200000UL ;
+ }
+ if (state->IF_LO == 37050000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 370500000UL ;
+ }
+ if (state->IF_LO == 36550000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 365500000UL ;
+ }
+ if (state->IF_LO == 36125000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 361250000UL ;
+ }
+ if (state->IF_LO == 6000000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 360000000UL ;
+ }
+ if (state->IF_LO == 5400000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 324000000UL ;
+ }
+ if (state->IF_LO == 5380000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C);
+ Fref = 322800000UL ;
+ }
+ if (state->IF_LO == 5200000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 374400000UL ;
+ }
+ if (state->IF_LO == 4900000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 352800000UL ;
+ }
+ if (state->IF_LO == 4400000UL) {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 352000000UL ;
+ }
+ if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ {
+ status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05);
+ status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08);
+ Fref = 365670000UL ;
+ }
+ }
+ /* CHCAL_INT_MOD_IF */
+ /* CHCAL_FRAC_MOD_IF */
+ intModVal = Fref / (state->Fxtal * Kdbl/2);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal);
+
+ fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) *
+ intModVal);
+
+ fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000);
+ status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal);
+
+ return status ;
+}
+
+static u32 MXL_GetXtalInt(u32 Xtal_Freq)
+{
+ if ((Xtal_Freq % 1000000) == 0)
+ return (Xtal_Freq / 10000);
+ else
+ return (((Xtal_Freq / 1000000) + 1)*100);
+}
+
+static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 status = 0;
+ u32 divider_val, E3, E4, E5, E5A;
+ u32 Fmax, Fmin, FmaxBin, FminBin;
+ u32 Kdbl_RF = 2;
+ u32 tg_divval;
+ u32 tg_lo;
+ u32 Xtal_Int;
+
+ u32 Fref_TG;
+ u32 Fvco;
+
+ Xtal_Int = MXL_GetXtalInt(state->Fxtal);
+
+ state->RF_IN = RF_Freq;
+
+ MXL_SynthRFTGLO_Calc(fe);
+
+ if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL)
+ Kdbl_RF = 2;
+ if (state->Fxtal > 22000000 && state->Fxtal <= 32000000)
+ Kdbl_RF = 1;
+
+ /* Downconverter Controls
+ * Look-Up Table Implementation for:
+ * DN_POLY
+ * DN_RFGAIN
+ * DN_CAP_RFLPF
+ * DN_EN_VHFUHFBAR
+ * DN_GAIN_ADJUST
+ * Change the boundary reference from RF_IN to RF_LO
+ */
+ if (state->RF_LO < 40000000UL)
+ return -1;
+
+ if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 2);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 3);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1);
+ }
+ if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 3);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 3);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1);
+ }
+ if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 3);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 3);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2);
+ }
+ if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 3);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 3);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2);
+ }
+ if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 3);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 3);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3);
+ }
+ if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 3);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 1);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3);
+ }
+ if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) {
+ status += MXL_ControlWrite(fe, DN_POLY, 3);
+ status += MXL_ControlWrite(fe, DN_RFGAIN, 2);
+ status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0);
+ status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0);
+ status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3);
+ }
+ if (state->RF_LO > 900000000UL)
+ return -1;
+
+ /* DN_IQTNBUF_AMP */
+ /* DN_IQTNGNBFBIAS_BST */
+ if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0);
+ }
+ if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1);
+ }
+ if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) {
+ status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10);
+ status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1);
+ }
+
+ /*
+ * Set RF Synth and LO Path Control
+ *
+ * Look-Up table implementation for:
+ * RFSYN_EN_OUTMUX
+ * RFSYN_SEL_VCO_OUT
+ * RFSYN_SEL_VCO_HI
+ * RFSYN_SEL_DIVM
+ * RFSYN_RF_DIV_BIAS
+ * DN_SEL_FREQ
+ *
+ * Set divider_val, Fmax, Fmix to use in Equations
+ */
+ FminBin = 28000000UL ;
+ FmaxBin = 42500000UL ;
+ if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1);
+ divider_val = 64 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 42500000UL ;
+ FmaxBin = 56000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1);
+ divider_val = 64 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 56000000UL ;
+ FmaxBin = 85000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1);
+ divider_val = 32 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 85000000UL ;
+ FmaxBin = 112000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1);
+ divider_val = 32 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 112000000UL ;
+ FmaxBin = 170000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2);
+ divider_val = 16 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 170000000UL ;
+ FmaxBin = 225000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2);
+ divider_val = 16 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 225000000UL ;
+ FmaxBin = 300000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4);
+ divider_val = 8 ;
+ Fmax = 340000000UL ;
+ Fmin = FminBin ;
+ }
+ FminBin = 300000000UL ;
+ FmaxBin = 340000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ divider_val = 8 ;
+ Fmax = FmaxBin ;
+ Fmin = 225000000UL ;
+ }
+ FminBin = 340000000UL ;
+ FmaxBin = 450000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ divider_val = 8 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 450000000UL ;
+ FmaxBin = 680000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ divider_val = 4 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 680000000UL ;
+ FmaxBin = 900000000UL ;
+ if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ divider_val = 4 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+
+ /* CHCAL_INT_MOD_RF
+ * CHCAL_FRAC_MOD_RF
+ * RFSYN_LPF_R
+ * CHCAL_EN_INT_RF
+ */
+ /* Equation E3 RFSYN_VCO_BIAS */
+ E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ;
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3);
+
+ /* Equation E4 CHCAL_INT_MOD_RF */
+ E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000);
+ MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4);
+
+ /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */
+ E5 = ((2<<17)*(state->RF_LO/10000*divider_val -
+ (E4*(2*state->Fxtal*Kdbl_RF)/10000))) /
+ (2*state->Fxtal*Kdbl_RF/10000);
+
+ status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
+
+ /* Equation E5A RFSYN_LPF_R */
+ E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ;
+ status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A);
+
+ /* Euqation E5B CHCAL_EN_INIT_RF */
+ status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0));
+ /*if (E5 == 0)
+ * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1);
+ *else
+ * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5);
+ */
+
+ /*
+ * Set TG Synth
+ *
+ * Look-Up table implementation for:
+ * TG_LO_DIVVAL
+ * TG_LO_SELVAL
+ *
+ * Set divider_val, Fmax, Fmix to use in Equations
+ */
+ if (state->TG_LO < 33000000UL)
+ return -1;
+
+ FminBin = 33000000UL ;
+ FmaxBin = 50000000UL ;
+ if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0);
+ divider_val = 36 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 50000000UL ;
+ FmaxBin = 67000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0);
+ divider_val = 24 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 67000000UL ;
+ FmaxBin = 100000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2);
+ divider_val = 18 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 100000000UL ;
+ FmaxBin = 150000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2);
+ divider_val = 12 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 150000000UL ;
+ FmaxBin = 200000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2);
+ divider_val = 8 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 200000000UL ;
+ FmaxBin = 300000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3);
+ divider_val = 6 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 300000000UL ;
+ FmaxBin = 400000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3);
+ divider_val = 4 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 400000000UL ;
+ FmaxBin = 600000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7);
+ divider_val = 3 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+ FminBin = 600000000UL ;
+ FmaxBin = 900000000UL ;
+ if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) {
+ status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0);
+ status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7);
+ divider_val = 2 ;
+ Fmax = FmaxBin ;
+ Fmin = FminBin ;
+ }
+
+ /* TG_DIV_VAL */
+ tg_divval = (state->TG_LO*divider_val/100000) *
+ (MXL_Ceiling(state->Fxtal, 1000000) * 100) /
+ (state->Fxtal/1000);
+
+ status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval);
+
+ if (state->TG_LO > 600000000UL)
+ status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1);
+
+ Fmax = 1800000000UL ;
+ Fmin = 1200000000UL ;
+
+ /* prevent overflow of 32 bit unsigned integer, use
+ * following equation. Edit for v2.6.4
+ */
+ /* Fref_TF = Fref_TG * 1000 */
+ Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000);
+
+ /* Fvco = Fvco/10 */
+ Fvco = (state->TG_LO/10000) * divider_val * Fref_TG;
+
+ tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8;
+
+ /* below equation is same as above but much harder to debug.
+ * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) -
+ * ((state->TG_LO/10000)*divider_val *
+ * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 *
+ * Xtal_Int/100) + 8;
+ */
+
+ status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo);
+
+ /* add for 2.6.5 Special setting for QAM */
+ if (state->Mod_Type == MXL_QAM) {
+ if (state->RF_IN < 680000000)
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+ else
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
+ }
+
+ /* Off Chip Tracking Filter Control */
+ if (state->TF_Type == MXL_TF_OFF) {
+ /* Tracking Filter Off State; turn off all the banks */
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */
+ status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */
+ status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */
+ }
+
+ if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ }
+ if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ }
+ if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ }
+ if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 0);
+ }
+ if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 29);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 0);
+ }
+ if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 0);
+ }
+ if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 16);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ }
+ if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 7);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ }
+ if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_C_H) {
+
+ /* Tracking Filter type C-H for Hauppauge only */
+ status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ }
+ if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ }
+ if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ }
+ if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ }
+ if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ }
+ if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ }
+ if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ }
+ if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ }
+ if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */
+
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_D_L) {
+
+ /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */
+ status += MXL_ControlWrite(fe, DAC_DIN_A, 0);
+
+ /* if UHF and terrestrial => Turn off Tracking Filter */
+ if (state->RF_IN >= 471000000 &&
+ (state->RF_IN - 471000000)%6000000 != 0) {
+ /* Turn off all the banks */
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_ControlWrite(fe, AGC_IF, 10);
+ } else {
+ /* if VHF or cable => Turn on Tracking Filter */
+ if (state->RF_IN >= 43000000 &&
+ state->RF_IN < 140000000) {
+
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 140000000 &&
+ state->RF_IN < 240000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 240000000 &&
+ state->RF_IN < 340000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 340000000 &&
+ state->RF_IN < 430000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 430000000 &&
+ state->RF_IN < 470000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 470000000 &&
+ state->RF_IN < 570000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 570000000 &&
+ state->RF_IN < 620000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 620000000 &&
+ state->RF_IN < 760000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 760000000 &&
+ state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ {
+
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_F) {
+
+ /* Tracking Filter type F */
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_E_2) {
+
+ /* Tracking Filter type E_2 */
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_G) {
+
+ /* Tracking Filter type G add for v2.6.8 */
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+ if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) {
+
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+
+ if (state->TF_Type == MXL_TF_E_NA) {
+
+ /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */
+ status += MXL_ControlWrite(fe, DAC_DIN_B, 0);
+
+ /* if UHF and terrestrial=> Turn off Tracking Filter */
+ if (state->RF_IN >= 471000000 &&
+ (state->RF_IN - 471000000)%6000000 != 0) {
+
+ /* Turn off all the banks */
+ status += MXL_SetGPIO(fe, 3, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+
+ /* 2.6.12 Turn on RSSI */
+ status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
+ status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1);
+ status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1);
+
+ /* RSSI reference point */
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3);
+ status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2);
+
+ /* following parameter is from analog OTA mode,
+ * can be change to seek better performance */
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
+ } else {
+ /* if VHF or Cable => Turn on Tracking Filter */
+
+ /* 2.6.12 Turn off RSSI */
+ status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
+
+ /* change back from above condition */
+ status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5);
+
+
+ if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) {
+
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 0);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 0);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 0);
+ }
+ if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) {
+ status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1);
+ status += MXL_SetGPIO(fe, 4, 1);
+ status += MXL_SetGPIO(fe, 1, 1);
+ status += MXL_SetGPIO(fe, 3, 1);
+ }
+ }
+ }
+ return status ;
+}
+
+static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val)
+{
+ u16 status = 0;
+
+ if (GPIO_Num == 1)
+ status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1);
+
+ /* GPIO2 is not available */
+
+ if (GPIO_Num == 3) {
+ if (GPIO_Val == 1) {
+ status += MXL_ControlWrite(fe, GPIO_3, 0);
+ status += MXL_ControlWrite(fe, GPIO_3B, 0);
+ }
+ if (GPIO_Val == 0) {
+ status += MXL_ControlWrite(fe, GPIO_3, 1);
+ status += MXL_ControlWrite(fe, GPIO_3B, 1);
+ }
+ if (GPIO_Val == 3) { /* tri-state */
+ status += MXL_ControlWrite(fe, GPIO_3, 0);
+ status += MXL_ControlWrite(fe, GPIO_3B, 1);
+ }
+ }
+ if (GPIO_Num == 4) {
+ if (GPIO_Val == 1) {
+ status += MXL_ControlWrite(fe, GPIO_4, 0);
+ status += MXL_ControlWrite(fe, GPIO_4B, 0);
+ }
+ if (GPIO_Val == 0) {
+ status += MXL_ControlWrite(fe, GPIO_4, 1);
+ status += MXL_ControlWrite(fe, GPIO_4B, 1);
+ }
+ if (GPIO_Val == 3) { /* tri-state */
+ status += MXL_ControlWrite(fe, GPIO_4, 0);
+ status += MXL_ControlWrite(fe, GPIO_4B, 1);
+ }
+ }
+
+ return status;
+}
+
+static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value)
+{
+ u16 status = 0;
+
+ /* Will write ALL Matching Control Name */
+ /* Write Matching INIT Control */
+ status += MXL_ControlWrite_Group(fe, ControlNum, value, 1);
+ /* Write Matching CH Control */
+ status += MXL_ControlWrite_Group(fe, ControlNum, value, 2);
+#ifdef _MXL_INTERNAL
+ /* Write Matching MXL Control */
+ status += MXL_ControlWrite_Group(fe, ControlNum, value, 3);
+#endif
+ return status;
+}
+
+static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum,
+ u32 value, u16 controlGroup)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 i, j, k;
+ u32 highLimit;
+ u32 ctrlVal;
+
+ if (controlGroup == 1) /* Initial Control */ {
+
+ for (i = 0; i < state->Init_Ctrl_Num; i++) {
+
+ if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
+
+ highLimit = 1 << state->Init_Ctrl[i].size;
+ if (value < highLimit) {
+ for (j = 0; j < state->Init_Ctrl[i].size; j++) {
+ state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+ MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]),
+ (u8)(state->Init_Ctrl[i].bit[j]),
+ (u8)((value>>j) & 0x01));
+ }
+ ctrlVal = 0;
+ for (k = 0; k < state->Init_Ctrl[i].size; k++)
+ ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k);
+ } else
+ return -1;
+ }
+ }
+ }
+ if (controlGroup == 2) /* Chan change Control */ {
+
+ for (i = 0; i < state->CH_Ctrl_Num; i++) {
+
+ if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
+
+ highLimit = 1 << state->CH_Ctrl[i].size;
+ if (value < highLimit) {
+ for (j = 0; j < state->CH_Ctrl[i].size; j++) {
+ state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+ MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]),
+ (u8)(state->CH_Ctrl[i].bit[j]),
+ (u8)((value>>j) & 0x01));
+ }
+ ctrlVal = 0;
+ for (k = 0; k < state->CH_Ctrl[i].size; k++)
+ ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
+ } else
+ return -1;
+ }
+ }
+ }
+#ifdef _MXL_INTERNAL
+ if (controlGroup == 3) /* Maxlinear Control */ {
+
+ for (i = 0; i < state->MXL_Ctrl_Num; i++) {
+
+ if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
+
+ highLimit = (1 << state->MXL_Ctrl[i].size);
+ if (value < highLimit) {
+ for (j = 0; j < state->MXL_Ctrl[i].size; j++) {
+ state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01);
+ MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]),
+ (u8)(state->MXL_Ctrl[i].bit[j]),
+ (u8)((value>>j) & 0x01));
+ }
+ ctrlVal = 0;
+ for (k = 0; k < state->MXL_Ctrl[i].size; k++)
+ ctrlVal += state->MXL_Ctrl[i].val[k] * (1 << k);
+ } else
+ return -1;
+ }
+ }
+ }
+#endif
+ return 0 ; /* successful return */
+}
+
+static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ int i ;
+
+ for (i = 0; i < 104; i++) {
+ if (RegNum == state->TunerRegs[i].Reg_Num) {
+ *RegVal = (u8)(state->TunerRegs[i].Reg_Val);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u32 ctrlVal ;
+ u16 i, k ;
+
+ for (i = 0; i < state->Init_Ctrl_Num ; i++) {
+
+ if (controlNum == state->Init_Ctrl[i].Ctrl_Num) {
+
+ ctrlVal = 0;
+ for (k = 0; k < state->Init_Ctrl[i].size; k++)
+ ctrlVal += state->Init_Ctrl[i].val[k] * (1<<k);
+ *value = ctrlVal;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < state->CH_Ctrl_Num ; i++) {
+
+ if (controlNum == state->CH_Ctrl[i].Ctrl_Num) {
+
+ ctrlVal = 0;
+ for (k = 0; k < state->CH_Ctrl[i].size; k++)
+ ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k);
+ *value = ctrlVal;
+ return 0;
+
+ }
+ }
+
+#ifdef _MXL_INTERNAL
+ for (i = 0; i < state->MXL_Ctrl_Num ; i++) {
+
+ if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) {
+
+ ctrlVal = 0;
+ for (k = 0; k < state->MXL_Ctrl[i].size; k++)
+ ctrlVal += state->MXL_Ctrl[i].val[k] * (1<<k);
+ *value = ctrlVal;
+ return 0;
+
+ }
+ }
+#endif
+ return 1;
+}
+
+static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit,
+ u8 bitVal)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ int i ;
+
+ const u8 AND_MAP[8] = {
+ 0xFE, 0xFD, 0xFB, 0xF7,
+ 0xEF, 0xDF, 0xBF, 0x7F } ;
+
+ const u8 OR_MAP[8] = {
+ 0x01, 0x02, 0x04, 0x08,
+ 0x10, 0x20, 0x40, 0x80 } ;
+
+ for (i = 0; i < state->TunerRegs_Num; i++) {
+ if (state->TunerRegs[i].Reg_Num == address) {
+ if (bitVal)
+ state->TunerRegs[i].Reg_Val |= OR_MAP[bit];
+ else
+ state->TunerRegs[i].Reg_Val &= AND_MAP[bit];
+ break ;
+ }
+ }
+}
+
+static u32 MXL_Ceiling(u32 value, u32 resolution)
+{
+ return (value/resolution + (value % resolution > 0 ? 1 : 0));
+}
+
+/* Retrieve the Initialzation Registers */
+static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
+ u8 *RegVal, int *count)
+{
+ u16 status = 0;
+ int i ;
+
+ u8 RegAddr[] = {
+ 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73,
+ 76, 77, 91, 134, 135, 137, 147,
+ 156, 166, 167, 168, 25 };
+
+ *count = sizeof(RegAddr) / sizeof(u8);
+
+ status += MXL_BlockInit(fe);
+
+ for (i = 0 ; i < *count; i++) {
+ RegNum[i] = RegAddr[i];
+ status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+ }
+
+ return status;
+}
+
+static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
+ int *count)
+{
+ u16 status = 0;
+ int i ;
+
+/* add 77, 166, 167, 168 register for 2.6.12 */
+#ifdef _MXL_PRODUCTION
+ u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106,
+ 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
+#else
+ u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106,
+ 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ;
+ /*
+ u8 RegAddr[171];
+ for (i = 0; i <= 170; i++)
+ RegAddr[i] = i;
+ */
+#endif
+
+ *count = sizeof(RegAddr) / sizeof(u8);
+
+ for (i = 0 ; i < *count; i++) {
+ RegNum[i] = RegAddr[i];
+ status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+ }
+
+ return status;
+}
+
+static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
+ u8 *RegVal, int *count)
+{
+ u16 status = 0;
+ int i;
+
+ u8 RegAddr[] = {43, 136};
+
+ *count = sizeof(RegAddr) / sizeof(u8);
+
+ for (i = 0; i < *count; i++) {
+ RegNum[i] = RegAddr[i];
+ status += MXL_RegRead(fe, RegNum[i], &RegVal[i]);
+ }
+
+ return status;
+}
+
+static u16 MXL_GetMasterControl(u8 *MasterReg, int state)
+{
+ if (state == 1) /* Load_Start */
+ *MasterReg = 0xF3;
+ if (state == 2) /* Power_Down */
+ *MasterReg = 0x41;
+ if (state == 3) /* Synth_Reset */
+ *MasterReg = 0xB1;
+ if (state == 4) /* Seq_Off */
+ *MasterReg = 0xF1;
+
+ return 0;
+}
+
+#ifdef _MXL_PRODUCTION
+static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 status = 0 ;
+
+ if (VCO_Range == 1) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ if (state->Mode == 0 && state->IF_Mode == 1) {
+ /* Analog Low IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 180224);
+ }
+ if (state->Mode == 0 && state->IF_Mode == 0) {
+ /* Analog Zero IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 222822);
+ }
+ if (state->Mode == 1) /* Digital Mode */ {
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 229376);
+ }
+ }
+
+ if (VCO_Range == 2) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
+ if (state->Mode == 0 && state->IF_Mode == 1) {
+ /* Analog Low IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 206438);
+ }
+ if (state->Mode == 0 && state->IF_Mode == 0) {
+ /* Analog Zero IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 206438);
+ }
+ if (state->Mode == 1) /* Digital Mode */ {
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 16384);
+ }
+ }
+
+ if (VCO_Range == 3) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+ if (state->Mode == 0 && state->IF_Mode == 1) {
+ /* Analog Low IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 173670);
+ }
+ if (state->Mode == 0 && state->IF_Mode == 0) {
+ /* Analog Zero IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 173670);
+ }
+ if (state->Mode == 1) /* Digital Mode */ {
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 245760);
+ }
+ }
+
+ if (VCO_Range == 4) {
+ status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1);
+ status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0);
+ status += MXL_ControlWrite(fe, RFSYN_DIVM, 1);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1);
+ status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1);
+ status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0);
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+ if (state->Mode == 0 && state->IF_Mode == 1) {
+ /* Analog Low IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 206438);
+ }
+ if (state->Mode == 0 && state->IF_Mode == 0) {
+ /* Analog Zero IF Mode */
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 206438);
+ }
+ if (state->Mode == 1) /* Digital Mode */ {
+ status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0);
+ status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40);
+ status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27);
+ status += MXL_ControlWrite(fe,
+ CHCAL_FRAC_MOD_RF, 212992);
+ }
+ }
+
+ return status;
+}
+
+static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u16 status = 0;
+
+ if (Hystersis == 1)
+ status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1);
+
+ return status;
+}
+#endif
+/* End: Reference driver code found in the Realtek driver that
+ * is copyright MaxLinear */
+
+/* ----------------------------------------------------------------
+ * Begin: Everything after here is new code to adapt the
+ * proprietary Realtek driver into a Linux API tuner.
+ * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ */
+static int mxl5005s_reset(struct dvb_frontend *fe)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ int ret = 0;
+
+ u8 buf[2] = { 0xff, 0x00 };
+ struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
+ .buf = buf, .len = 2 };
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mxl5005s I2C reset failed\n");
+ ret = -EREMOTEIO;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+/* Write a single byte to a single reg, latch the value if required by
+ * following the transaction with the latch byte.
+ */
+static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE };
+ struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
+ .buf = buf, .len = 3 };
+
+ if (latch == 0)
+ msg.len = 2;
+
+ dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr);
+
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mxl5005s I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable,
+ u8 *datatable, u8 len)
+{
+ int ret = 0, i;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ for (i = 0 ; i < len-1; i++) {
+ ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0);
+ if (ret < 0)
+ break;
+ }
+
+ ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+static int mxl5005s_init(struct dvb_frontend *fe)
+{
+ dprintk(1, "%s()\n", __func__);
+ return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
+}
+
+static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type,
+ u32 bandwidth)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+
+ u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+ u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
+ int TableLen;
+
+ dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth);
+
+ mxl5005s_reset(fe);
+
+ /* Tuner initialization stage 0 */
+ MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
+ AddrTable[0] = MASTER_CONTROL_ADDR;
+ ByteTable[0] |= state->config->AgcMasterByte;
+
+ mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
+
+ mxl5005s_AssignTunerMode(fe, mod_type, bandwidth);
+
+ /* Tuner initialization stage 1 */
+ MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen);
+
+ mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
+
+ return 0;
+}
+
+static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
+ u32 bandwidth)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ struct mxl5005s_config *c = state->config;
+
+ InitTunerControls(fe);
+
+ /* Set MxL5005S parameters. */
+ MXL5005_TunerConfig(
+ fe,
+ c->mod_mode,
+ c->if_mode,
+ bandwidth,
+ c->if_freq,
+ c->xtal_freq,
+ c->agc_mode,
+ c->top,
+ c->output_load,
+ c->clock_out,
+ c->div_out,
+ c->cap_select,
+ c->rssi_enable,
+ mod_type,
+ c->tracking_filter);
+
+ return 0;
+}
+
+static int mxl5005s_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ u32 req_mode, req_bw = 0;
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (fe->ops.info.type == FE_ATSC) {
+ switch (params->u.vsb.modulation) {
+ case VSB_8:
+ req_mode = MXL_ATSC; break;
+ default:
+ case QAM_64:
+ case QAM_256:
+ case QAM_AUTO:
+ req_mode = MXL_QAM; break;
+ }
+ } else
+ req_mode = MXL_DVBT;
+
+ /* Change tuner for new modulation type if reqd */
+ if (req_mode != state->current_mode) {
+ switch (req_mode) {
+ case VSB_8:
+ case QAM_64:
+ case QAM_256:
+ case QAM_AUTO:
+ req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ break;
+ default:
+ /* Assume DVB-T */
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ req_bw = MXL5005S_BANDWIDTH_6MHZ;
+ break;
+ case BANDWIDTH_7_MHZ:
+ req_bw = MXL5005S_BANDWIDTH_7MHZ;
+ break;
+ case BANDWIDTH_AUTO:
+ case BANDWIDTH_8_MHZ:
+ req_bw = MXL5005S_BANDWIDTH_8MHZ;
+ break;
+ }
+ }
+
+ state->current_mode = req_mode;
+ ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
+
+ } else
+ ret = 0;
+
+ if (ret == 0) {
+ dprintk(1, "%s() freq=%d\n", __func__, params->frequency);
+ ret = mxl5005s_SetRfFreqHz(fe, params->frequency);
+ }
+
+ return ret;
+}
+
+static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ dprintk(1, "%s()\n", __func__);
+
+ *frequency = state->RF_IN;
+
+ return 0;
+}
+
+static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mxl5005s_state *state = fe->tuner_priv;
+ dprintk(1, "%s()\n", __func__);
+
+ *bandwidth = state->Chan_Bandwidth;
+
+ return 0;
+}
+
+static int mxl5005s_release(struct dvb_frontend *fe)
+{
+ dprintk(1, "%s()\n", __func__);
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mxl5005s_tuner_ops = {
+ .info = {
+ .name = "MaxLinear MXL5005S",
+ .frequency_min = 48000000,
+ .frequency_max = 860000000,
+ .frequency_step = 50000,
+ },
+
+ .release = mxl5005s_release,
+ .init = mxl5005s_init,
+
+ .set_params = mxl5005s_set_params,
+ .get_frequency = mxl5005s_get_frequency,
+ .get_bandwidth = mxl5005s_get_bandwidth,
+};
+
+struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mxl5005s_config *config)
+{
+ struct mxl5005s_state *state = NULL;
+ dprintk(1, "%s()\n", __func__);
+
+ state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->frontend = fe;
+ state->config = config;
+ state->i2c = i2c;
+ state->current_mode = MXL_QAM;
+
+ printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n",
+ config->i2c_address);
+
+ memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = state;
+ return fe;
+}
+EXPORT_SYMBOL(mxl5005s_attach);
+
+MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h
new file mode 100644
index 000000000000..396db150bf0c
--- /dev/null
+++ b/drivers/media/common/tuners/mxl5005s.h
@@ -0,0 +1,131 @@
+/*
+ MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
+
+ Copyright (C) 2008 MaxLinear
+ Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __MXL5005S_H
+#define __MXL5005S_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct mxl5005s_config {
+
+ /* 7 bit i2c address */
+ u8 i2c_address;
+
+#define IF_FREQ_4570000HZ 4570000
+#define IF_FREQ_4571429HZ 4571429
+#define IF_FREQ_5380000HZ 5380000
+#define IF_FREQ_36000000HZ 36000000
+#define IF_FREQ_36125000HZ 36125000
+#define IF_FREQ_36166667HZ 36166667
+#define IF_FREQ_44000000HZ 44000000
+ u32 if_freq;
+
+#define CRYSTAL_FREQ_4000000HZ 4000000
+#define CRYSTAL_FREQ_16000000HZ 16000000
+#define CRYSTAL_FREQ_25000000HZ 25000000
+#define CRYSTAL_FREQ_28800000HZ 28800000
+ u32 xtal_freq;
+
+#define MXL_DUAL_AGC 0
+#define MXL_SINGLE_AGC 1
+ u8 agc_mode;
+
+#define MXL_TF_DEFAULT 0
+#define MXL_TF_OFF 1
+#define MXL_TF_C 2
+#define MXL_TF_C_H 3
+#define MXL_TF_D 4
+#define MXL_TF_D_L 5
+#define MXL_TF_E 6
+#define MXL_TF_F 7
+#define MXL_TF_E_2 8
+#define MXL_TF_E_NA 9
+#define MXL_TF_G 10
+ u8 tracking_filter;
+
+#define MXL_RSSI_DISABLE 0
+#define MXL_RSSI_ENABLE 1
+ u8 rssi_enable;
+
+#define MXL_CAP_SEL_DISABLE 0
+#define MXL_CAP_SEL_ENABLE 1
+ u8 cap_select;
+
+#define MXL_DIV_OUT_1 0
+#define MXL_DIV_OUT_4 1
+ u8 div_out;
+
+#define MXL_CLOCK_OUT_DISABLE 0
+#define MXL_CLOCK_OUT_ENABLE 1
+ u8 clock_out;
+
+#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200
+#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300
+ u32 output_load;
+
+#define MXL5005S_TOP_5P5 55
+#define MXL5005S_TOP_7P2 72
+#define MXL5005S_TOP_9P2 92
+#define MXL5005S_TOP_11P0 110
+#define MXL5005S_TOP_12P9 129
+#define MXL5005S_TOP_14P7 147
+#define MXL5005S_TOP_16P8 168
+#define MXL5005S_TOP_19P4 194
+#define MXL5005S_TOP_21P2 212
+#define MXL5005S_TOP_23P2 232
+#define MXL5005S_TOP_25P2 252
+#define MXL5005S_TOP_27P1 271
+#define MXL5005S_TOP_29P2 292
+#define MXL5005S_TOP_31P7 317
+#define MXL5005S_TOP_34P9 349
+ u32 top;
+
+#define MXL_ANALOG_MODE 0
+#define MXL_DIGITAL_MODE 1
+ u8 mod_mode;
+
+#define MXL_ZERO_IF 0
+#define MXL_LOW_IF 1
+ u8 if_mode;
+
+ /* Stuff I don't know what to do with */
+ u8 AgcMasterByte;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \
+ (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mxl5005s_config *config);
+#else
+static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mxl5005s_config *config)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MXL5005S */
+
+#endif /* __MXL5005S_H */
+
diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/common/tuners/qt1010.c
index 825aa1412e6f..825aa1412e6f 100644
--- a/drivers/media/dvb/frontends/qt1010.c
+++ b/drivers/media/common/tuners/qt1010.c
diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/common/tuners/qt1010.h
index cff6a7ca5380..807fb7b6146b 100644
--- a/drivers/media/dvb/frontends/qt1010.h
+++ b/drivers/media/common/tuners/qt1010.h
@@ -36,7 +36,7 @@ struct qt1010_config {
* @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))
+#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE))
extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct qt1010_config *cfg);
@@ -48,6 +48,6 @@ static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_QT1010
+#endif // CONFIG_MEDIA_TUNER_QT1010
#endif
diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h
index 090cf475f099..090cf475f099 100644
--- a/drivers/media/dvb/frontends/qt1010_priv.h
+++ b/drivers/media/common/tuners/qt1010_priv.h
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index e27a7620a32f..42b5f5d4bfe6 100644
--- a/drivers/media/dvb/frontends/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -227,9 +227,8 @@ int tda18271_charge_pump_source(struct dvb_frontend *fe,
regs[r_cp] &= ~0x20;
regs[r_cp] |= ((force & 1) << 5);
- tda18271_write_regs(fe, r_cp, 1);
- return 0;
+ return tda18271_write_regs(fe, r_cp, 1);
}
int tda18271_init_regs(struct dvb_frontend *fe)
@@ -487,16 +486,15 @@ int tda18271_set_standby_mode(struct dvb_frontend *fe,
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
- tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+ if (tda18271_debug & DBG_ADV)
+ tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */
regs[R_EP3] |= sm ? (1 << 7) : 0 |
sm_lt ? (1 << 6) : 0 |
sm_xt ? (1 << 5) : 0;
- tda18271_write_regs(fe, R_EP3, 1);
-
- return 0;
+ return tda18271_write_regs(fe, R_EP3, 1);
}
/*---------------------------------------------------------------------*/
@@ -510,7 +508,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
u32 div;
int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_MPD] = (0x77 & pd);
@@ -542,7 +540,7 @@ int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
u32 div;
int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_CPD] = pd;
@@ -566,7 +564,7 @@ int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
u8 val;
int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_EP1] &= ~0x07; /* clear bp filter bits */
@@ -583,7 +581,7 @@ int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
u8 val;
int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_EB13] &= ~0x7c; /* clear k & m bits */
@@ -600,7 +598,7 @@ int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
u8 val;
int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_EP2] &= ~0xe0; /* clear rf band bits */
@@ -617,7 +615,7 @@ int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
u8 val;
int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_EP2] &= ~0x1f; /* clear gain taper bits */
@@ -634,7 +632,7 @@ int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
u8 val;
int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
regs[R_EP5] &= ~0x07;
diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index b262100ae897..89c01fb1f859 100644
--- a/drivers/media/dvb/frontends/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -51,6 +51,7 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
+ int ret;
u32 N;
/* update TV broadcast parameters */
@@ -85,7 +86,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
/* update rf top / if top */
regs[R_EB22] = 0x00;
regs[R_EB22] |= map->rfagc_top;
- tda18271_write_regs(fe, R_EB22, 1);
+ ret = tda18271_write_regs(fe, R_EB22, 1);
+ if (tda_fail(ret))
+ goto fail;
/* --------------------------------------------------------------- */
@@ -121,7 +124,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
/* agc1 has priority on agc2 */
regs[R_EB1] &= ~0x01;
- tda18271_write_regs(fe, R_EB1, 1);
+ ret = tda18271_write_regs(fe, R_EB1, 1);
+ if (tda_fail(ret))
+ goto fail;
/* --------------------------------------------------------------- */
@@ -141,7 +146,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
break;
}
- tda18271_write_regs(fe, R_TM, 7);
+ ret = tda18271_write_regs(fe, R_TM, 7);
+ if (tda_fail(ret))
+ goto fail;
/* force charge pump source */
charge_pump_source(fe, 1);
@@ -158,9 +165,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
regs[R_EP3] &= ~0x04;
else
regs[R_EP3] |= 0x04;
- tda18271_write_regs(fe, R_EP3, 1);
-
- return 0;
+ ret = tda18271_write_regs(fe, R_EP3, 1);
+fail:
+ return ret;
}
static int tda18271_read_thermometer(struct dvb_frontend *fe)
@@ -213,11 +220,13 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
struct tda18271_priv *priv = fe->tuner_priv;
struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
unsigned char *regs = priv->tda18271_regs;
- int tm_current, rfcal_comp, approx, i;
+ int tm_current, rfcal_comp, approx, i, ret;
u8 dc_over_dt, rf_tab;
/* power up */
- tda18271_set_standby_mode(fe, 0, 0, 0);
+ ret = tda18271_set_standby_mode(fe, 0, 0, 0);
+ if (tda_fail(ret))
+ goto fail;
/* read die current temperature */
tm_current = tda18271_read_thermometer(fe);
@@ -228,8 +237,8 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
rf_tab = regs[R_EB14];
i = tda18271_lookup_rf_band(fe, &freq, NULL);
- if (i < 0)
- return -EINVAL;
+ if (tda_fail(i))
+ return i;
if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
approx = map[i].rf_a1 *
@@ -250,35 +259,42 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
regs[R_EB14] = approx + rfcal_comp;
- tda18271_write_regs(fe, R_EB14, 1);
-
- return 0;
+ ret = tda18271_write_regs(fe, R_EB14, 1);
+fail:
+ return ret;
}
static int tda18271_por(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
+ int ret;
/* power up detector 1 */
regs[R_EB12] &= ~0x20;
- tda18271_write_regs(fe, R_EB12, 1);
+ ret = tda18271_write_regs(fe, R_EB12, 1);
+ if (tda_fail(ret))
+ goto fail;
regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */
- tda18271_write_regs(fe, R_EB18, 1);
+ ret = tda18271_write_regs(fe, R_EB18, 1);
+ if (tda_fail(ret))
+ goto fail;
regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
/* POR mode */
- tda18271_set_standby_mode(fe, 1, 0, 0);
+ ret = tda18271_set_standby_mode(fe, 1, 0, 0);
+ if (tda_fail(ret))
+ goto fail;
/* disable 1.5 MHz low pass filter */
regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
- tda18271_write_regs(fe, R_EB21, 3);
-
- return 0;
+ ret = tda18271_write_regs(fe, R_EB21, 3);
+fail:
+ return ret;
}
static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
@@ -389,7 +405,7 @@ static int tda18271_powerscan(struct dvb_frontend *fe,
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
- int sgn, bcal, count, wait;
+ int sgn, bcal, count, wait, ret;
u8 cid_target;
u16 count_limit;
u32 freq;
@@ -421,7 +437,9 @@ static int tda18271_powerscan(struct dvb_frontend *fe,
tda18271_write_regs(fe, R_EP2, 1);
/* read power detection info, stored in EB10 */
- tda18271_read_extended(fe);
+ ret = tda18271_read_extended(fe);
+ if (tda_fail(ret))
+ return ret;
/* algorithm initialization */
sgn = 1;
@@ -447,7 +465,9 @@ static int tda18271_powerscan(struct dvb_frontend *fe,
tda18271_write_regs(fe, R_EP2, 1);
/* read power detection info, stored in EB10 */
- tda18271_read_extended(fe);
+ ret = tda18271_read_extended(fe);
+ if (tda_fail(ret))
+ return ret;
count += 200;
@@ -478,6 +498,7 @@ static int tda18271_powerscan_init(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
+ int ret;
/* set standard to digital */
regs[R_EP3] &= ~0x1f; /* clear std bits */
@@ -489,10 +510,14 @@ static int tda18271_powerscan_init(struct dvb_frontend *fe)
/* update IF output level & IF notch frequency */
regs[R_EP4] &= ~0x1c; /* clear if level bits */
- tda18271_write_regs(fe, R_EP3, 2);
+ ret = tda18271_write_regs(fe, R_EP3, 2);
+ if (tda_fail(ret))
+ goto fail;
regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */
- tda18271_write_regs(fe, R_EB18, 1);
+ ret = tda18271_write_regs(fe, R_EB18, 1);
+ if (tda_fail(ret))
+ goto fail;
regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
@@ -500,9 +525,9 @@ static int tda18271_powerscan_init(struct dvb_frontend *fe)
regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
- tda18271_write_regs(fe, R_EB21, 3);
-
- return 0;
+ ret = tda18271_write_regs(fe, R_EB21, 3);
+fail:
+ return ret;
}
static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
@@ -521,7 +546,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
i = tda18271_lookup_rf_band(fe, &freq, NULL);
- if (i < 0)
+ if (tda_fail(i))
return i;
rf_default[RF1] = 1000 * map[i].rf1_def;
@@ -535,6 +560,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
/* look for optimized calibration frequency */
bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
+ if (tda_fail(bcal))
+ return bcal;
tda18271_calc_rf_cal(fe, &rf_freq[rf]);
prog_tab[rf] = regs[R_EB14];
@@ -575,22 +602,29 @@ static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned int i;
+ int ret;
tda_info("tda18271: performing RF tracking filter calibration\n");
/* wait for die temperature stabilization */
msleep(200);
- tda18271_powerscan_init(fe);
+ ret = tda18271_powerscan_init(fe);
+ if (tda_fail(ret))
+ goto fail;
/* rf band calibration */
- for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
+ for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) {
+ ret =
tda18271_rf_tracking_filters_init(fe, 1000 *
priv->rf_cal_state[i].rfmax);
+ if (tda_fail(ret))
+ goto fail;
+ }
priv->tm_rfcal = tda18271_read_thermometer(fe);
-
- return 0;
+fail:
+ return ret;
}
/* ------------------------------------------------------------------ */
@@ -599,6 +633,7 @@ static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
+ int ret;
/* test RF_CAL_OK to see if we need init */
if ((regs[R_EP1] & 0x10) == 0)
@@ -607,15 +642,22 @@ static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
if (priv->cal_initialized)
return 0;
- tda18271_calc_rf_filter_curve(fe);
+ ret = tda18271_calc_rf_filter_curve(fe);
+ if (tda_fail(ret))
+ goto fail;
- tda18271_por(fe);
+ ret = tda18271_por(fe);
+ if (tda_fail(ret))
+ goto fail;
tda_info("tda18271: RF tracking filter calibration complete\n");
priv->cal_initialized = true;
-
- return 0;
+ goto end;
+fail:
+ tda_info("tda18271: RF tracking filter calibration failed!\n");
+end:
+ return ret;
}
static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
@@ -623,6 +665,7 @@ static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
+ int ret;
u32 N = 0;
/* calculate bp filter */
@@ -671,7 +714,10 @@ static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
tda18271_calc_main_pll(fe, N);
- tda18271_write_regs(fe, R_EP3, 11);
+ ret = tda18271_write_regs(fe, R_EP3, 11);
+ if (tda_fail(ret))
+ return ret;
+
msleep(5); /* RF tracking filter calibration initialization */
/* search for K,M,CO for RF calibration */
@@ -719,45 +765,56 @@ static int tda18271_ir_cal_init(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
+ int ret;
- tda18271_read_regs(fe);
+ ret = tda18271_read_regs(fe);
+ if (tda_fail(ret))
+ goto fail;
/* test IR_CAL_OK to see if we need init */
if ((regs[R_EP1] & 0x08) == 0)
- tda18271_init_regs(fe);
-
- return 0;
+ ret = tda18271_init_regs(fe);
+fail:
+ return ret;
}
static int tda18271_init(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
+ int ret;
mutex_lock(&priv->lock);
/* power up */
- tda18271_set_standby_mode(fe, 0, 0, 0);
+ ret = tda18271_set_standby_mode(fe, 0, 0, 0);
+ if (tda_fail(ret))
+ goto fail;
/* initialization */
- tda18271_ir_cal_init(fe);
+ ret = tda18271_ir_cal_init(fe);
+ if (tda_fail(ret))
+ goto fail;
if (priv->id == TDA18271HDC2)
tda18271c2_rf_cal_init(fe);
-
+fail:
mutex_unlock(&priv->lock);
- return 0;
+ return ret;
}
static int tda18271_tune(struct dvb_frontend *fe,
struct tda18271_std_map_item *map, u32 freq, u32 bw)
{
struct tda18271_priv *priv = fe->tuner_priv;
+ int ret;
tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
freq, map->if_freq, bw, map->agc_mode, map->std);
- tda18271_init(fe);
+ ret = tda18271_init(fe);
+ if (tda_fail(ret))
+ goto fail;
mutex_lock(&priv->lock);
@@ -769,11 +826,11 @@ static int tda18271_tune(struct dvb_frontend *fe,
tda18271c2_rf_tracking_filters_correction(fe, freq);
break;
}
- tda18271_channel_configuration(fe, map, freq, bw);
+ ret = tda18271_channel_configuration(fe, map, freq, bw);
mutex_unlock(&priv->lock);
-
- return 0;
+fail:
+ return ret;
}
/* ------------------------------------------------------------------ */
@@ -837,7 +894,7 @@ static int tda18271_set_params(struct dvb_frontend *fe,
ret = tda18271_tune(fe, map, freq, bw);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
priv->frequency = freq;
@@ -893,7 +950,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe,
ret = tda18271_tune(fe, map, freq, 0);
- if (ret < 0)
+ if (tda_fail(ret))
goto fail;
priv->frequency = freq;
@@ -905,16 +962,17 @@ fail:
static int tda18271_sleep(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
+ int ret;
mutex_lock(&priv->lock);
/* standby mode w/ slave tuner output
* & loop thru & xtal oscillator on */
- tda18271_set_standby_mode(fe, 1, 0, 0);
+ ret = tda18271_set_standby_mode(fe, 1, 0, 0);
mutex_unlock(&priv->lock);
- return 0;
+ return ret;
}
static int tda18271_release(struct dvb_frontend *fe)
@@ -1095,10 +1153,10 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
if (cfg)
priv->small_i2c = cfg->small_i2c;
- if (tda18271_get_id(fe) < 0)
+ if (tda_fail(tda18271_get_id(fe)))
goto fail;
- if (tda18271_assign_map_layout(fe) < 0)
+ if (tda_fail(tda18271_assign_map_layout(fe)))
goto fail;
mutex_lock(&priv->lock);
diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/common/tuners/tda18271-maps.c
index 83e7561960c1..83e7561960c1 100644
--- a/drivers/media/dvb/frontends/tda18271-tables.c
+++ b/drivers/media/common/tuners/tda18271-maps.c
diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
index 2bc5eb368ea2..81a739365f8c 100644
--- a/drivers/media/dvb/frontends/tda18271-priv.h
+++ b/drivers/media/common/tuners/tda18271-priv.h
@@ -153,6 +153,15 @@ extern int tda18271_debug;
#define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg)
#define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg)
+#define tda_fail(ret) \
+({ \
+ int __ret; \
+ __ret = (ret < 0); \
+ if (__ret) \
+ tda_printk(KERN_ERR, "error %d on line %d\n", ret, __LINE__);\
+ __ret; \
+})
+
/*---------------------------------------------------------------------*/
enum tda18271_map_type {
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/common/tuners/tda18271.h
index 0e7af8d05a38..7db9831c0cb0 100644
--- a/drivers/media/dvb/frontends/tda18271.h
+++ b/drivers/media/common/tuners/tda18271.h
@@ -81,7 +81,7 @@ struct tda18271_config {
unsigned int small_i2c:1;
};
-#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct i2c_adapter *i2c,
struct tda18271_config *cfg);
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/common/tuners/tda827x.c
index d30d2c9094d9..d30d2c9094d9 100644
--- a/drivers/media/dvb/frontends/tda827x.c
+++ b/drivers/media/common/tuners/tda827x.c
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/common/tuners/tda827x.h
index b73c23570dab..7850a9a1dc8f 100644
--- a/drivers/media/dvb/frontends/tda827x.h
+++ b/drivers/media/common/tuners/tda827x.h
@@ -51,7 +51,7 @@ struct tda827x_config
* @param cfg optional callback function pointers.
* @return FE pointer on success, NULL on failure.
*/
-#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE))
extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
struct tda827x_config *cfg);
@@ -64,6 +64,6 @@ static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe,
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TDA827X
+#endif // CONFIG_MEDIA_TUNER_TDA827X
#endif // __DVB_TDA827X_H__
diff --git a/drivers/media/video/tda8290.c b/drivers/media/common/tuners/tda8290.c
index 0ebb5b525e57..91204d3f282d 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -578,16 +578,16 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
if ((data == 0x83) || (data == 0x84)) {
priv->ver |= TDA18271;
- tda18271_attach(fe, priv->tda827x_addr,
- priv->i2c_props.adap,
- &tda829x_tda18271_config);
+ dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
+ priv->i2c_props.adap, &tda829x_tda18271_config);
} else {
if ((data & 0x3c) == 0)
priv->ver |= TDA8275;
else
priv->ver |= TDA8275A;
- tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg);
+ dvb_attach(tda827x_attach, fe, priv->tda827x_addr,
+ priv->i2c_props.adap, &priv->cfg);
priv->cfg.switch_addr = priv->i2c_props.addr;
}
if (fe->ops.tuner_ops.init)
diff --git a/drivers/media/video/tda8290.h b/drivers/media/common/tuners/tda8290.h
index d3bbf276a469..aa074f3f0c07 100644
--- a/drivers/media/video/tda8290.h
+++ b/drivers/media/common/tuners/tda8290.h
@@ -29,7 +29,7 @@ struct tda829x_config {
#define TDA829X_DONT_PROBE 1
};
-#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE))
extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/video/tda9887.c b/drivers/media/common/tuners/tda9887.c
index a0545ba957b0..a0545ba957b0 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/common/tuners/tda9887.c
diff --git a/drivers/media/video/tda9887.h b/drivers/media/common/tuners/tda9887.h
index be49dcbfc70e..acc419e8c4fc 100644
--- a/drivers/media/video/tda9887.h
+++ b/drivers/media/common/tuners/tda9887.h
@@ -21,7 +21,7 @@
#include "dvb_frontend.h"
/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/video/tea5761.c b/drivers/media/common/tuners/tea5761.c
index b93cdef9ac73..b93cdef9ac73 100644
--- a/drivers/media/video/tea5761.c
+++ b/drivers/media/common/tuners/tea5761.c
diff --git a/drivers/media/video/tea5761.h b/drivers/media/common/tuners/tea5761.h
index 8eb62722b988..2e2ff82c95a4 100644
--- a/drivers/media/video/tea5761.h
+++ b/drivers/media/common/tuners/tea5761.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/video/tea5767.c b/drivers/media/common/tuners/tea5767.c
index f6e7d7ad8424..1f5646334a8f 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/common/tuners/tea5767.c
@@ -373,14 +373,14 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
- return EINVAL;
+ return -EINVAL;
}
/* If all bytes are the same then it's a TV tuner and not a tea5767 */
if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
- return EINVAL;
+ return -EINVAL;
}
/* Status bytes:
@@ -390,7 +390,7 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
*/
if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
- return EINVAL;
+ return -EINVAL;
}
diff --git a/drivers/media/video/tea5767.h b/drivers/media/common/tuners/tea5767.h
index 7b547c092e25..d30ab1b483de 100644
--- a/drivers/media/video/tea5767.h
+++ b/drivers/media/common/tuners/tea5767.h
@@ -39,7 +39,7 @@ struct tea5767_ctrl {
enum tea5767_xtal xtal_freq;
};
-#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE))
extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h
index 3ad6c8e0b04c..3ad6c8e0b04c 100644
--- a/drivers/media/video/tuner-i2c.h
+++ b/drivers/media/common/tuners/tuner-i2c.h
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index be8d903171b7..be8d903171b7 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h
index e46cf0121e03..381fa5d35a9b 100644
--- a/drivers/media/video/tuner-simple.h
+++ b/drivers/media/common/tuners/tuner-simple.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE))
extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index 10dddca8b5d1..10dddca8b5d1 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h
index 74dc46a71f64..74dc46a71f64 100644
--- a/drivers/media/video/tuner-xc2028-types.h
+++ b/drivers/media/common/tuners/tuner-xc2028-types.h
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 9e9003cffc7f..9e9003cffc7f 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index fc2f132a5541..216025cf5d4b 100644
--- a/drivers/media/video/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -47,7 +47,7 @@ struct xc2028_config {
#define XC2028_TUNER_RESET 0
#define XC2028_RESET_CLK 1
-#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
struct xc2028_config *cfg);
#else
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 43d35bdb221f..ceae6db901ec 100644
--- a/drivers/media/dvb/frontends/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -212,7 +212,7 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
dprintk(1, "%s()\n", __func__);
if (priv->cfg->tuner_callback) {
- ret = priv->cfg->tuner_callback(priv->cfg->priv,
+ ret = priv->cfg->tuner_callback(priv->devptr,
XC5000_TUNER_RESET, 0);
if (ret)
printk(KERN_ERR "xc5000: reset failed\n");
@@ -900,9 +900,9 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
.get_status = xc5000_get_status
};
-struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct xc5000_config *cfg)
+struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct xc5000_config *cfg, void *devptr)
{
struct xc5000_priv *priv = NULL;
u16 id = 0;
@@ -916,6 +916,7 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
priv->cfg = cfg;
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->i2c = i2c;
+ priv->devptr = devptr;
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/common/tuners/xc5000.h
index b890883a0cdc..c910715addc9 100644
--- a/drivers/media/dvb/frontends/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -31,33 +31,35 @@ struct xc5000_config {
u8 i2c_address;
u32 if_khz;
- /* For each bridge framework, when it attaches either analog or digital,
- * it has to store a reference back to its _core equivalent structure,
- * so that it can service the hardware by steering gpio's etc.
- * Each bridge implementation is different so cast priv accordingly.
- * The xc5000 driver cares not for this value, other than ensuring
- * it's passed back to a bridge during tuner_callback().
- */
- void *priv;
int (*tuner_callback) (void *priv, int command, int arg);
};
/* xc5000 callback command */
#define XC5000_TUNER_RESET 0
-#if defined(CONFIG_DVB_TUNER_XC5000) || \
- (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE))
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc5000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
+#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
+ (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg);
+ struct xc5000_config *cfg,
+ void *devptr);
#else
static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg)
+ struct xc5000_config *cfg,
+ void *devptr)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_XC5000
+#endif // CONFIG_MEDIA_TUNER_XC5000
#endif // __XC5000_H__
diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
index 13b2d19341da..ecebfe4745ad 100644
--- a/drivers/media/dvb/frontends/xc5000_priv.h
+++ b/drivers/media/common/tuners/xc5000_priv.h
@@ -31,6 +31,8 @@ struct xc5000_priv {
u8 video_standard;
u8 rf_mode;
u8 fwloaded;
+
+ void *devptr;
};
#endif
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 03ef88acd9b8..7b21b49f1945 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -1,9 +1,7 @@
#
-# Multimedia device configuration
+# DVB device configuration
#
-source "drivers/media/dvb/dvb-core/Kconfig"
-
menuconfig DVB_CAPTURE_DRIVERS
bool "DVB/ATSC adapters"
depends on DVB_CORE
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 6ec5afba1ca7..73dc2ee9b014 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,7 +9,7 @@ config DVB_B2C2_FLEXCOP
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index 870e2848c296..d9db066f9854 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -14,4 +14,4 @@ b2c2-flexcop-usb-objs = flexcop-usb.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-EXTRA_CFLAGS += -Idrivers/media/video/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 7b0ea3bdfafb..f9d087669d5d 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -634,7 +634,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
}
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
- fc->fe = dvb_attach(vp310_mt312_attach,
+ fc->fe = dvb_attach(mt312_attach,
&skystar23_samsung_tbdu18132_config, i2c);
if (fc->fe != NULL) {
ops = &fc->fe->ops;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 902c762e0b7f..7588db1319d0 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,6 +1,7 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
+ depends on HOTPLUG # due to FW_LOADER
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_SP887X if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
@@ -8,7 +9,7 @@ config DVB_BT8XX
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 9d3e68b5d6eb..d98f1d49ffa8 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -3,4 +3,4 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
-EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 75711bde23ad..a7637562e742 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1714,7 +1714,7 @@ static void dst_release(struct dvb_frontend *fe)
struct dst_state *state = fe->demodulator_priv;
if (state->dst_ca) {
dvb_unregister_device(state->dst_ca);
-#ifdef CONFIG_DVB_CORE_ATTACH
+#ifdef CONFIG_MEDIA_ATTACH
symbol_put(dst_ca_attach);
#endif
}
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 3d778c5aba68..c03513b2ccae 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -1,6 +1,6 @@
config DVB_CINERGYT2
tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
- depends on DVB_CORE && USB
+ depends on DVB_CORE && USB && INPUT
help
Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
deleted file mode 100644
index e3e6839f8073..000000000000
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ /dev/null
@@ -1,34 +0,0 @@
-config DVB_CORE
- tristate "DVB for Linux"
- depends on NET && INET
- select CRC32
- help
- Support Digital Video Broadcasting hardware. Enable this if you
- own a DVB adapter and want to use it or if you compile Linux for
- a digital SetTopBox.
-
- DVB core utility functions for device handling, software fallbacks etc.
- Say Y when you have a DVB card and want to use it. Say Y if your want
- to build your drivers outside the kernel, but need the DVB core. All
- in-kernel drivers will select this automatically if needed.
-
- API specs and user tools are available from <http://www.linuxtv.org/>.
-
- Please report problems regarding this driver to the LinuxDVB
- mailing list.
-
- If unsure say N.
-
-config DVB_CORE_ATTACH
- bool "Load and attach frontend modules as needed"
- depends on DVB_CORE
- depends on MODULES
- help
- Remove the static dependency of DVB card drivers on all
- frontend modules for all possible card variants. Instead,
- allow the card drivers to only load the frontend modules
- they require. This saves several KBytes of memory.
-
- Note: You will need module-init-tools v3.2 or later for this feature.
-
- If unsure say Y.
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 8cbdb0ec67e2..588fbe105c27 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -910,15 +910,21 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
int curdelay = 100000000;
int slot;
+ /* Beware of too high polling frequency, because one polling
+ * call might take several hundred milliseconds until timeout!
+ */
for (slot = 0; slot < ca->slot_count; slot++) {
switch (ca->slot_info[slot].slot_state) {
default:
case DVB_CA_SLOTSTATE_NONE:
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ * 5; /* 5s */
+ break;
case DVB_CA_SLOTSTATE_INVALID:
- delay = HZ * 60;
- if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
- delay = HZ / 10;
- }
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ / 10; /* 100ms */
break;
case DVB_CA_SLOTSTATE_UNINITIALISED:
@@ -926,19 +932,17 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
case DVB_CA_SLOTSTATE_VALIDATE:
case DVB_CA_SLOTSTATE_WAITFR:
case DVB_CA_SLOTSTATE_LINKINIT:
- delay = HZ / 10;
+ delay = HZ / 10; /* 100ms */
break;
case DVB_CA_SLOTSTATE_RUNNING:
- delay = HZ * 60;
- if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
- delay = HZ / 10;
- }
+ delay = HZ * 60; /* 60s */
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+ delay = HZ / 10; /* 100ms */
if (ca->open) {
if ((!ca->slot_info[slot].da_irq_supported) ||
- (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
- delay = HZ / 10;
- }
+ (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+ delay = HZ / 10; /* 100ms */
}
break;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 2dddd08c5445..8cbdb218952f 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1189,7 +1189,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
}
EXPORT_SYMBOL(dvb_unregister_frontend);
-#ifdef CONFIG_DVB_CORE_ATTACH
+#ifdef CONFIG_MEDIA_ATTACH
void dvb_frontend_detach(struct dvb_frontend* fe)
{
void *ptr;
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 5f9a737c6de1..89d12dc477a7 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -115,7 +115,7 @@ extern int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
/** generic DVB attach function. */
-#ifdef CONFIG_DVB_CORE_ATTACH
+#ifdef CONFIG_MEDIA_ATTACH
#define dvb_attach(FUNCTION, ARGS...) ({ \
void *__r = NULL; \
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 3c8493d2026d..cf4584e48b6d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,7 @@
config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C
+ depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
help
By enabling this you will be able to choose the various supported
@@ -25,7 +26,7 @@ config DVB_USB_A800
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
depends on DVB_USB
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
@@ -35,7 +36,7 @@ config DVB_USB_DIBUSB_MB
depends on DVB_USB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MB
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -56,7 +57,7 @@ config DVB_USB_DIBUSB_MC
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
Support for USB2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -73,8 +74,8 @@ config DVB_USB_DIB0700
select DVB_DIB7000P
select DVB_DIB7000M
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070
help
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -93,7 +94,7 @@ config DVB_USB_UMT_010
depends on DVB_USB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
@@ -105,7 +106,7 @@ config DVB_USB_CXUSB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -118,7 +119,7 @@ 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
+ select MEDIA_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
@@ -129,7 +130,7 @@ 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
+ select MEDIA_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.
@@ -138,7 +139,7 @@ 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
+ select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
@@ -190,7 +191,7 @@ config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
@@ -227,8 +228,8 @@ config DVB_USB_OPERA1
config DVB_USB_AF9005
tristate "Afatech AF9005 DVB-T USB1.1 support"
depends on DVB_USB && EXPERIMENTAL
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
and the TerraTec Cinergy T USB XE (Rev.1)
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 60a910052c16..c6511a6c0ab8 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -63,5 +63,5 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
-EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index f5fceb3cdb3c..c20553c4da1f 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -15,22 +15,36 @@ config DVB_FE_CUSTOMISE
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
-config DVB_STV0299
- tristate "ST STV0299 based"
+config DVB_CX24110
+ tristate "Conexant CX24110 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_CX24110
- tristate "Conexant CX24110 based"
+config DVB_CX24123
+ tristate "Conexant CX24123 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_CX24123
- tristate "Conexant CX24123 based"
+config DVB_MT312
+ tristate "Zarlink VP310/MT312/ZL10313 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_S5H1420
+ tristate "Samsung S5H1420 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_STV0299
+ tristate "ST STV0299 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@@ -43,8 +57,8 @@ config DVB_TDA8083
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_MT312
- tristate "Zarlink VP310/MT312 based"
+config DVB_TDA10086
+ tristate "Philips TDA10086 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@@ -57,26 +71,33 @@ config DVB_VES1X93
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_S5H1420
- tristate "Samsung S5H1420 based"
+config DVB_TUNER_ITD1000
+ tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_TDA10086
- tristate "Philips TDA10086 based"
+config DVB_TDA826X
+ tristate "Philips TDA826X silicon tuner"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
- A DVB-S tuner module. Say Y when you want to support this frontend.
+ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_TUA6100
+ tristate "Infineon TUA6100 PLL"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S PLL chip.
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_SP8870
tristate "Spase sp8870 based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -89,7 +110,7 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -123,7 +144,7 @@ config DVB_L64781
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -190,7 +211,7 @@ config DVB_DIB7000P
config DVB_TDA10048
tristate "Philips TDA10048HN based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -232,7 +253,7 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -247,7 +268,7 @@ config DVB_NXT200X
config DVB_OR51211
tristate "Oren OR51211 based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -260,7 +281,7 @@ config DVB_OR51211
config DVB_OR51132
tristate "Oren OR51132 based"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -276,7 +297,7 @@ config DVB_OR51132
config DVB_BCM3510
tristate "Broadcom BCM3510"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && HOTPLUG
default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
@@ -315,7 +336,7 @@ config DVB_S5H1411
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
-comment "Tuners/PLL support"
+comment "Digital terrestrial only tuners/PLL"
depends on DVB_CORE
config DVB_PLL
@@ -326,55 +347,6 @@ config DVB_PLL
This module drives a number of tuners based on PLL chips with a
common I2C interface. Say Y when you want to support these tuners.
-config DVB_TDA826X
- tristate "Philips TDA826X silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TDA827X
- tristate "Philips TDA827X silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TDA18271
- tristate "NXP TDA18271 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A 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
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon IF tuner MT2060 from Microtune.
-
-config DVB_TUNER_MT2266
- tristate "Microtune MT2266 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon baseband tuner MT2266 from Microtune.
-
-config DVB_TUNER_MT2131
- tristate "Microtune MT2131 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon baseband tuner MT2131 from Microtune.
-
config DVB_TUNER_DIB0070
tristate "DiBcom DiB0070 silicon base-band tuner"
depends on I2C
@@ -384,21 +356,7 @@ config DVB_TUNER_DIB0070
This device is only used inside a SiP called togther with a
demodulator for now.
-config DVB_TUNER_XC5000
- tristate "Xceive XC5000 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon tuner XC5000 from Xceive.
- This device is only used inside a SiP called togther with a
- demodulator for now.
-
-config DVB_TUNER_ITD1000
- tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
-
-comment "Miscellaneous devices"
+comment "SEC control devices for DVB-S"
depends on DVB_CORE
config DVB_LNBP21
@@ -422,11 +380,4 @@ config DVB_ISL6421
help
An SEC control chip.
-config DVB_TUA6100
- tristate "TUA6100 PLL"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVBS PLL chip.
-
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 9747c73dc826..a89dc0fc4c6f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -3,9 +3,7 @@
#
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-EXTRA_CFLAGS += -Idrivers/media/video/
-
-tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -42,16 +40,9 @@ obj-$(CONFIG_DVB_ISL6405) += isl6405.o
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
-obj-$(CONFIG_DVB_TDA827X) += tda827x.o
-obj-$(CONFIG_DVB_TDA18271) += tda18271.o
-obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
-obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
-obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
-obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
-obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c
index 04c562ccf990..600dad6b41ea 100644
--- a/drivers/media/dvb/frontends/itd1000.c
+++ b/drivers/media/dvb/frontends/itd1000.c
@@ -195,7 +195,7 @@ static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
}
}
-struct {
+static const struct {
u32 freq;
u8 values[10]; /* RFTR, RFST1 - RFST9 */
} itd1000_fre_values[] = {
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 081ca3398c76..5ac9b15920f8 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -737,7 +737,7 @@ static void mt312_release(struct dvb_frontend *fe)
}
#define MT312_SYS_CLK 90000000UL /* 90 MHz */
-static struct dvb_frontend_ops vp310_mt312_ops = {
+static struct dvb_frontend_ops mt312_ops = {
.info = {
.name = "Zarlink ???? DVB-S",
@@ -776,7 +776,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
.set_voltage = mt312_set_voltage,
};
-struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+struct dvb_frontend *mt312_attach(const struct mt312_config *config,
struct i2c_adapter *i2c)
{
struct mt312_state *state = NULL;
@@ -795,7 +795,7 @@ struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
goto error;
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &vp310_mt312_ops,
+ memcpy(&state->frontend.ops, &mt312_ops,
sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
@@ -827,12 +827,13 @@ error:
kfree(state);
return NULL;
}
-EXPORT_SYMBOL(vp310_mt312_attach);
+EXPORT_SYMBOL(mt312_attach);
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index de796eab3911..29e3bb5496b8 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -37,10 +37,10 @@ struct mt312_config {
};
#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
-struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+struct dvb_frontend *mt312_attach(const struct mt312_config *config,
struct i2c_adapter *i2c);
#else
-static inline struct dvb_frontend *vp310_mt312_attach(
+static inline struct dvb_frontend *mt312_attach(
const struct mt312_config *config, struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 281e1cb2edc6..720ed9ff7c5f 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -481,7 +481,7 @@ static void s5h1420_setsymbolrate(struct s5h1420_state* state,
val *= 2;
do_div(val, (state->fclk / 1000));
- dprintk("symbol rate register: %06llx\n", val);
+ dprintk("symbol rate register: %06llx\n", (unsigned long long)val);
v = s5h1420_readreg(state, Loop01);
s5h1420_writereg(state, Loop01, v & 0x7f);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index ae882432dd3d..d4339b1b3b68 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -5,6 +5,7 @@ config TTPCI_EEPROM
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
+ depends on HOTPLUG
select FW_LOADER if !DVB_AV7110_FIRMWARE
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
@@ -123,6 +124,7 @@ config DVB_BUDGET_AV
depends on DVB_BUDGET_CORE && I2C
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
+ depends on HOTPLUG # dependency of FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
index 83611012ef34..0712899e39a4 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -1,6 +1,7 @@
config DVB_TTUSB_DEC
tristate "Technotrend/Hauppauge USB DEC devices"
depends on DVB_CORE && USB
+ depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
select CRC32
help
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index fe9a4cc14141..89d8d37838a3 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1,4 +1,54 @@
#
+# Generic video config states
+#
+
+config VIDEO_V4L2
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON
+ default VIDEO_DEV && VIDEO_V4L2_COMMON
+
+config VIDEO_V4L1
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+ default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+
+config VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DMA_SG
+ depends on HAS_DMA
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_VMALLOC
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DVB
+ tristate
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+
+config VIDEO_BTCX
+ tristate
+
+config VIDEO_IR_I2C
+ tristate
+
+config VIDEO_IR
+ tristate
+ depends on INPUT
+ select VIDEO_IR_I2C if I2C
+
+config VIDEO_TVEEPROM
+ tristate
+ depends on I2C
+
+config VIDEO_TUNER
+ tristate
+ depends on MEDIA_TUNER
+
+#
# Multimedia Video device configuration
#
@@ -702,6 +752,8 @@ source "drivers/media/video/au0828/Kconfig"
source "drivers/media/video/ivtv/Kconfig"
+source "drivers/media/video/cx18/Kconfig"
+
config VIDEO_M32R_AR
tristate "AR devices"
depends on M32R && VIDEO_V4L1
@@ -858,7 +910,7 @@ config SOC_CAMERA
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
- depends on SOC_CAMERA
+ depends on SOC_CAMERA && I2C
select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
help
This driver supports MT9M001 cameras from Micron, monochrome
@@ -873,7 +925,7 @@ config MT9M001_PCA9536_SWITCH
config SOC_CAMERA_MT9V022
tristate "mt9v022 support"
- depends on SOC_CAMERA
+ depends on SOC_CAMERA && I2C
select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
help
This driver supports MT9V022 cameras from Micron
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index be14227f3726..dff0d6abe917 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -86,16 +86,6 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
-obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
-# tuner-types will be merged into tuner-simple, in the future
-obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o
-obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
-obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
-obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
-obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
-obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
-
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
@@ -134,6 +124,7 @@ obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -147,3 +138,4 @@ obj-$(CONFIG_VIDEO_AU0828) += au0828/
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index 41708267e7a4..def10d086373 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -1,10 +1,11 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
- depends on VIDEO_DEV && I2C && INPUT && DVB_CORE
+ depends on VIDEO_DEV && I2C && INPUT && DVB_CORE && USB
select I2C_ALGOBIT
+ select VIDEO_TVEEPROM
select DVB_AU8522 if !DVB_FE_CUSTOMIZE
- select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Auvitek's USB device.
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
index 9f4f572c89c5..cd2c58281b4e 100644
--- a/drivers/media/video/au0828/Makefile
+++ b/drivers/media/video/au0828/Makefile
@@ -2,7 +2,7 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
-EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 1371b4e4b5f1..c86a5f17eca8 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -337,12 +337,10 @@ int au0828_dvb_register(struct au0828_dev *dev)
dvb->frontend = dvb_attach(au8522_attach,
&hauppauge_hvr950q_config,
&dev->i2c_adap);
- if (dvb->frontend != NULL) {
- hauppauge_hvr950q_tunerconfig.priv = dev;
+ if (dvb->frontend != NULL)
dvb_attach(xc5000_attach, dvb->frontend,
&dev->i2c_adap,
- &hauppauge_hvr950q_tunerconfig);
- }
+ &hauppauge_hvr950q_tunerconfig, dev);
break;
default:
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index cfc822bb502a..24a34fc1f2b3 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
+ depends on HOTPLUG # due to FW_LOADER
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
index 924d216d9570..e415f6fc447c 100644
--- a/drivers/media/video/bt8xx/Makefile
+++ b/drivers/media/video/bt8xx/Makefile
@@ -9,4 +9,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
obj-$(CONFIG_VIDEO_BT848) += bttv.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 03816b73f847..27da7b423275 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -81,8 +81,6 @@
/* 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)
-
#define BTTV_NORMS (\
V4L2_STD_PAL | V4L2_STD_PAL_N | \
V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index fae469ce16f5..03411503457e 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -142,7 +142,8 @@ static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
/* ----------------------------------------------------------------------- */
-static int cs5345_probe(struct i2c_client *client)
+static int cs5345_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -159,10 +160,17 @@ static int cs5345_probe(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id cs5345_id[] = {
+ { "cs5345", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs5345_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs5345",
.driverid = I2C_DRIVERID_CS5345,
.command = cs5345_command,
.probe = cs5345_probe,
+ .id_table = cs5345_id,
};
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index f41bfde045fe..d965af860ab2 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -135,7 +135,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int cs53l32a_probe(struct i2c_client *client)
+static int cs53l32a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i;
@@ -143,7 +144,8 @@ static int cs53l32a_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+ if (!id)
+ strlcpy(client->name, "cs53l32a", sizeof(client->name));
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -174,10 +176,17 @@ static int cs53l32a_probe(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id cs53l32a_id[] = {
+ { "cs53l32a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs53l32a",
.driverid = I2C_DRIVERID_CS53L32A,
.command = cs53l32a_command,
.probe = cs53l32a_probe,
+ .id_table = cs53l32a_id,
};
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
new file mode 100644
index 000000000000..5f942690570c
--- /dev/null
+++ b/drivers/media/video/cx18/Kconfig
@@ -0,0 +1,23 @@
+config VIDEO_CX18
+ tristate "Conexant cx23418 MPEG encoder support"
+ depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
+ depends on INPUT # due to VIDEO_IR
+ depends on HOTPLUG # due to FW_LOADER
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_IR
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+ select VIDEO_CS5345
+ select DVB_S5H1409
+ select MEDIA_TUNER_MXL5005S
+ ---help---
+ This is a video4linux driver for Conexant cx23418 based
+ PCI combo video recorder devices.
+
+ This is used in devices such as the Hauppauge HVR-1600
+ cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx18.
diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile
new file mode 100644
index 000000000000..b23d2e26120f
--- /dev/null
+++ b/drivers/media/video/cx18/Makefile
@@ -0,0 +1,11 @@
+cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
+ cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
+ cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
+ cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
+ cx18-dvb.o
+
+obj-$(CONFIG_VIDEO_CX18) += cx18.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
new file mode 100644
index 000000000000..1adc404d955e
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -0,0 +1,73 @@
+/*
+ * cx18 audio-related functions
+ *
+ * Derived from ivtv-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-i2c.h"
+#include "cx18-cards.h"
+#include "cx18-audio.h"
+
+/* Selects the audio input and output according to the current
+ settings. */
+int cx18_audio_set_io(struct cx18 *cx)
+{
+ struct v4l2_routing route;
+ u32 audio_input;
+ int mux_input;
+
+ /* Determine which input to use */
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ audio_input = cx->card->radio_input.audio_input;
+ mux_input = cx->card->radio_input.muxer_input;
+ } else {
+ audio_input =
+ cx->card->audio_inputs[cx->audio_input].audio_input;
+ mux_input =
+ cx->card->audio_inputs[cx->audio_input].muxer_input;
+ }
+
+ /* handle muxer chips */
+ route.input = mux_input;
+ route.output = 0;
+ cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+ route.input = audio_input;
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ VIDIOC_INT_S_AUDIO_ROUTING, &route);
+}
+
+void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
+{
+ cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ VIDIOC_INT_S_AUDIO_ROUTING, route);
+}
+
+void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq)
+{
+ static u32 freqs[3] = { 44100, 48000, 32000 };
+
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (freq > 2)
+ return;
+ cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
+}
diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h
new file mode 100644
index 000000000000..cb569a69379c
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-audio.h
@@ -0,0 +1,26 @@
+/*
+ * cx18 audio-related functions
+ *
+ * Derived from ivtv-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_audio_set_io(struct cx18 *cx);
+void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route);
+void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq);
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
new file mode 100644
index 000000000000..2dc3a5dd170e
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -0,0 +1,361 @@
+/*
+ * cx18 ADEC audio functions
+ *
+ * Derived from cx25840-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 "cx18-driver.h"
+
+static int set_audclk_freq(struct cx18 *cx, u32 freq)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ if (freq != 32000 && freq != 44100 && freq != 48000)
+ return -EINVAL;
+
+ /* common for all inputs and rates */
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+ cx18_av_write(cx, 0x127, 0x50);
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ switch (freq) {
+ case 32000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1006040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x01bb39ee);
+
+ /* src3/4/6_ctl = 0x0801f77f */
+ cx18_av_write4(cx, 0x900, 0x0801f77f);
+ cx18_av_write4(cx, 0x904, 0x0801f77f);
+ cx18_av_write4(cx, 0x90c, 0x0801f77f);
+ break;
+
+ case 44100:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1009040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x00ec6bd6);
+
+ /* src3/4/6_ctl = 0x08016d59 */
+ cx18_av_write4(cx, 0x900, 0x08016d59);
+ cx18_av_write4(cx, 0x904, 0x08016d59);
+ cx18_av_write4(cx, 0x90c, 0x08016d59);
+ break;
+
+ case 48000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x100a040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x0098d6e5);
+
+ /* src3/4/6_ctl = 0x08014faa */
+ cx18_av_write4(cx, 0x900, 0x08014faa);
+ cx18_av_write4(cx, 0x904, 0x08014faa);
+ cx18_av_write4(cx, 0x90c, 0x08014faa);
+ break;
+ }
+ } else {
+ switch (freq) {
+ case 32000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1e08040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x012a0869);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x08010000);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08020000);
+ cx18_av_write4(cx, 0x904, 0x08020000);
+ cx18_av_write4(cx, 0x90c, 0x08020000);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+ cx18_av_write(cx, 0x127, 0x54);
+ break;
+
+ case 44100:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1809040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x00ec6bd6);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x080160cd);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08017385);
+ cx18_av_write4(cx, 0x904, 0x08017385);
+ cx18_av_write4(cx, 0x90c, 0x08017385);
+ break;
+
+ case 48000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x180a040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x0098d6e5);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x08018000);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08015555);
+ cx18_av_write4(cx, 0x904, 0x08015555);
+ cx18_av_write4(cx, 0x90c, 0x08015555);
+ break;
+ }
+ }
+
+ state->audclk_freq = freq;
+
+ return 0;
+}
+
+void cx18_av_audio_set_path(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ /* stop microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0);
+
+ /* assert soft reset */
+ cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
+
+ /* Mute everything to prevent the PFFT! */
+ cx18_av_write(cx, 0x8d3, 0x1f);
+
+ if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+ /* Set Path1 to Serial Audio Input */
+ cx18_av_write4(cx, 0x8d0, 0x01011012);
+
+ /* The microcontroller should not be started for the
+ * non-tuner inputs: autodetection is specific for
+ * TV audio. */
+ } else {
+ /* Set Path1 to Analog Demod Main Channel */
+ cx18_av_write4(cx, 0x8d0, 0x1f063870);
+ }
+
+ set_audclk_freq(cx, state->audclk_freq);
+
+ /* deassert soft reset */
+ cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int get_volume(struct cx18 *cx)
+{
+ /* Volume runs +18dB to -96dB in 1/2dB steps
+ * change to fit the msp3400 -114dB to +12dB range */
+
+ /* check PATH1_VOLUME */
+ int vol = 228 - cx18_av_read(cx, 0x8d4);
+ vol = (vol / 2) + 23;
+ return vol << 9;
+}
+
+static void set_volume(struct cx18 *cx, int volume)
+{
+ /* First convert the volume to msp3400 values (0-127) */
+ int vol = volume >> 9;
+ /* now scale it up to cx18_av values
+ * -114dB to -96dB maps to 0
+ * this should be 19, but in my testing that was 4dB too loud */
+ if (vol <= 23)
+ vol = 0;
+ else
+ vol -= 23;
+
+ /* PATH1_VOLUME */
+ cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
+}
+
+static int get_bass(struct cx18 *cx)
+{
+ /* bass is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_BASS_VOL */
+ int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
+ bass = (((48 - bass) * 0xffff) + 47) / 48;
+ return bass;
+}
+
+static void set_bass(struct cx18 *cx, int bass)
+{
+ /* PATH1_EQ_BASS_VOL */
+ cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+static int get_treble(struct cx18 *cx)
+{
+ /* treble is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_TREBLE_VOL */
+ int treble = cx18_av_read(cx, 0x8db) & 0x3f;
+ treble = (((48 - treble) * 0xffff) + 47) / 48;
+ return treble;
+}
+
+static void set_treble(struct cx18 *cx, int treble)
+{
+ /* PATH1_EQ_TREBLE_VOL */
+ cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+static int get_balance(struct cx18 *cx)
+{
+ /* balance is 7 bit, 0 to -96dB */
+
+ /* check PATH1_BAL_LEVEL */
+ int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
+ /* check PATH1_BAL_LEFT */
+ if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
+ balance = 0x80 - balance;
+ else
+ balance = 0x80 + balance;
+ return balance << 8;
+}
+
+static void set_balance(struct cx18 *cx, int balance)
+{
+ int bal = balance >> 8;
+ if (bal > 0x80) {
+ /* PATH1_BAL_LEFT */
+ cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
+ /* PATH1_BAL_LEVEL */
+ cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
+ } else {
+ /* PATH1_BAL_LEFT */
+ cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
+ /* PATH1_BAL_LEVEL */
+ cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
+ }
+}
+
+static int get_mute(struct cx18 *cx)
+{
+ /* check SRC1_MUTE_EN */
+ return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
+}
+
+static void set_mute(struct cx18 *cx, int mute)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ /* Must turn off microcontroller in order to mute sound.
+ * Not sure if this is the best method, but it does work.
+ * If the microcontroller is running, then it will undo any
+ * changes to the mute register. */
+ if (mute) {
+ /* disable microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+ cx18_av_write(cx, 0x8d3, 0x1f);
+ } else {
+ /* enable microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+ } else {
+ /* SRC1_MUTE_EN */
+ cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ }
+}
+
+int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_control *ctrl = arg;
+ int retval;
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ cx18_av_and_or(cx, 0x803, ~0x10, 0);
+ cx18_av_write(cx, 0x8d3, 0x1f);
+ }
+ cx18_av_and_or(cx, 0x810, ~0x1, 1);
+ retval = set_audclk_freq(cx, *(u32 *)arg);
+ cx18_av_and_or(cx, 0x810, ~0x1, 0);
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ return retval;
+
+ case VIDIOC_G_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = get_volume(cx);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = get_bass(cx);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = get_treble(cx);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = get_balance(cx);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = get_mute(cx);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_S_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ set_volume(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ set_bass(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ set_treble(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ set_balance(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ set_mute(cx, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
new file mode 100644
index 000000000000..66864904c99b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -0,0 +1,879 @@
+/*
+ * cx18 ADEC audio functions
+ *
+ * Derived from cx25840-core.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 "cx18-driver.h"
+
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
+{
+ u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+ u32 mask = 0xff;
+ int shift = (addr & 3) * 8;
+
+ x = (x & ~(mask << shift)) | ((u32)value << shift);
+ writel(x, cx->reg_mem + 0xc40000 + (addr & ~3));
+ return 0;
+}
+
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
+{
+ writel(value, cx->reg_mem + 0xc40000 + addr);
+ return 0;
+}
+
+u8 cx18_av_read(struct cx18 *cx, u16 addr)
+{
+ u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+ int shift = (addr & 3) * 8;
+
+ return (x >> shift) & 0xff;
+}
+
+u32 cx18_av_read4(struct cx18 *cx, u16 addr)
+{
+ return readl(cx->reg_mem + 0xc40000 + addr);
+}
+
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
+ u8 or_value)
+{
+ return cx18_av_write(cx, addr,
+ (cx18_av_read(cx, addr) & and_mask) |
+ or_value);
+}
+
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
+ u32 or_value)
+{
+ return cx18_av_write4(cx, addr,
+ (cx18_av_read4(cx, addr) & and_mask) |
+ or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input);
+static void log_audio_status(struct cx18 *cx);
+static void log_video_status(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+
+static void cx18_av_initialize(struct cx18 *cx)
+{
+ u32 v;
+
+ cx18_av_loadfw(cx);
+ /* Stop 8051 code execution */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000);
+
+ /* initallize the PLL by toggling sleep bit */
+ v = cx18_av_read4(cx, CXADEC_HOST_REG1);
+ /* enable sleep mode */
+ cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1);
+ /* disable sleep mode */
+ cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe);
+
+ /* initialize DLLs */
+ v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
+ /* disable FLD */
+ cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v);
+ /* enable FLD */
+ cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100);
+
+ v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF;
+ /* disable FLD */
+ cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v);
+ /* enable FLD */
+ cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100);
+
+ /* set analog bias currents. Set Vreg to 1.20V. */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802);
+
+ v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
+ /* enable TUNE_FIL_RST */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v);
+ /* disable TUNE_FIL_RST */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE);
+
+ /* enable 656 output */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
+
+ /* video output drive strength */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2);
+
+ /* reset video */
+ cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
+ cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
+
+ /* set video to auto-detect */
+ /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */
+ /* set the comb notch = 1 */
+ cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800);
+
+ /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */
+ /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */
+ cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000);
+
+ /* Set VGA_TRACK_RANGE to 0x20 */
+ cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
+
+ /* Enable VBI capture */
+ cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
+ /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
+
+ /* Set the video input.
+ The setting in MODE_CTRL gets lost when we do the above setup */
+ /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
+ /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
+
+ v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+ v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */
+ v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */
+ v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */
+ /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */
+ cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
+
+/* if(dwEnable && dw3DCombAvailable) { */
+/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
+/* } else { */
+/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
+/* } */
+ cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+
+ /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
+ if (std & V4L2_STD_SECAM)
+ cx18_av_write(cx, 0x402, 0);
+ else {
+ cx18_av_write(cx, 0x402, 0x04);
+ cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+ }
+ cx18_av_and_or(cx, 0x401, ~0x60, 0);
+ cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
+
+ if (std & V4L2_STD_525_60) {
+ if (std == V4L2_STD_NTSC_M_JP) {
+ /* Japan uses EIAJ audio standard */
+ cx18_av_write(cx, 0x808, 0xf7);
+ } else if (std == V4L2_STD_NTSC_M_KR) {
+ /* South Korea uses A2 audio standard */
+ cx18_av_write(cx, 0x808, 0xf8);
+ } else {
+ /* Others use the BTSC audio standard */
+ cx18_av_write(cx, 0x808, 0xf6);
+ }
+ cx18_av_write(cx, 0x80b, 0x00);
+ } else if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx18_av_write(cx, 0x808, 0xff);
+ cx18_av_write(cx, 0x80b, 0x03);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx18_av_write(cx, 0x808, 0xff);
+ cx18_av_write(cx, 0x80b, 0x03);
+ }
+
+ if (cx18_av_read(cx, 0x803) & 0x10) {
+ /* restart audio decoder microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8);
+ u8 reg;
+
+ CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
+ vid_input, aud_input);
+
+ if (is_composite) {
+ reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+ } else {
+ int luma = vid_input & 0xf0;
+ int chroma = vid_input & 0xf00;
+
+ if ((vid_input & ~0xff0) ||
+ luma < CX18_AV_SVIDEO_LUMA1 ||
+ luma > CX18_AV_SVIDEO_LUMA4 ||
+ chroma < CX18_AV_SVIDEO_CHROMA4 ||
+ chroma > CX18_AV_SVIDEO_CHROMA8) {
+ CX18_ERR("0x%04x is not a valid video input!\n",
+ vid_input);
+ return -EINVAL;
+ }
+ reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+ if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
+ reg &= 0x3f;
+ reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+ } else {
+ reg &= 0xcf;
+ reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+ }
+ }
+
+ switch (aud_input) {
+ case CX18_AV_AUDIO_SERIAL:
+ /* do nothing, use serial audio input */
+ break;
+ case CX18_AV_AUDIO4: reg &= ~0x30; break;
+ case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+ case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+ case CX18_AV_AUDIO7: reg &= ~0xc0; break;
+ case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+
+ default:
+ CX18_ERR("0x%04x is not a valid audio input!\n", aud_input);
+ return -EINVAL;
+ }
+
+ cx18_av_write(cx, 0x103, reg);
+ /* Set INPUT_MODE to Composite (0) or S-Video (1) */
+ cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+ /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+ cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+ /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+ if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+ cx18_av_and_or(cx, 0x102, ~0x4, 4);
+ else
+ cx18_av_and_or(cx, 0x102, ~0x4, 0);
+ /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
+
+ state->vid_input = vid_input;
+ state->aud_input = aud_input;
+ cx18_av_audio_set_path(cx);
+ input_change(cx);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 fmt = 0; /* zero is autodetect */
+ u8 pal_m = 0;
+
+ /* First tests should be against specific std */
+ if (state->std == V4L2_STD_NTSC_M_JP) {
+ fmt = 0x2;
+ } else if (state->std == V4L2_STD_NTSC_443) {
+ fmt = 0x3;
+ } else if (state->std == V4L2_STD_PAL_M) {
+ pal_m = 1;
+ fmt = 0x5;
+ } else if (state->std == V4L2_STD_PAL_N) {
+ fmt = 0x6;
+ } else if (state->std == V4L2_STD_PAL_Nc) {
+ fmt = 0x7;
+ } else if (state->std == V4L2_STD_PAL_60) {
+ fmt = 0x8;
+ } else {
+ /* Then, test against generic ones */
+ if (state->std & V4L2_STD_NTSC)
+ fmt = 0x1;
+ else if (state->std & V4L2_STD_PAL)
+ fmt = 0x4;
+ else if (state->std & V4L2_STD_SECAM)
+ fmt = 0xc;
+ }
+
+ CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt);
+
+ /* Follow step 9 of section 3.16 in the cx18_av datasheet.
+ Without this PAL may display a vertical ghosting effect.
+ This happens for example with the Yuan MPC622. */
+ if (fmt >= 4 && fmt < 8) {
+ /* Set format to NTSC-M */
+ cx18_av_and_or(cx, 0x400, ~0xf, 1);
+ /* Turn off LCOMB */
+ cx18_av_and_or(cx, 0x47b, ~6, 0);
+ }
+ cx18_av_and_or(cx, 0x400, ~0xf, fmt);
+ cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+ cx18_av_vbi_setup(cx);
+ input_change(cx);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ CX18_ERR("invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x414, ctrl->value - 128);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ CX18_ERR("invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x415, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ CX18_ERR("invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x420, ctrl->value << 1);
+ cx18_av_write(cx, 0x421, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ CX18_ERR("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x422, ctrl->value);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = cx18_av_read(cx, 0x415) >> 1;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = cx18_av_read(cx, 0x420) >> 1;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = (s8)cx18_av_read(cx, 0x422);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_pix_format *pix;
+ int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+ int is_50Hz = !(state->std & V4L2_STD_525_60);
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pix = &(fmt->fmt.pix);
+
+ Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
+
+ Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+
+ Vlines = pix->height + (is_50Hz ? 4 : 7);
+
+ if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ CX18_ERR("%dx%d is not a valid size!\n",
+ pix->width, pix->height);
+ return -ERANGE;
+ }
+
+ HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (pix->width >= 385)
+ filter = 0;
+ else if (pix->width > 192)
+ filter = 1;
+ else if (pix->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n",
+ pix->width, pix->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx18_av_write(cx, 0x418, HSC & 0xff);
+ cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
+ cx18_av_write(cx, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx18_av_write(cx, 0x41c, VSC & 0xff);
+ cx18_av_write(cx, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx18_av_write(cx, 0x41e, 0x8 | filter);
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_tuner *vt = arg;
+ struct v4l2_routing *route = arg;
+
+ /* ignore these commands */
+ switch (cmd) {
+ case TUNER_SET_TYPE_ADDR:
+ return 0;
+ }
+
+ if (!state->is_initialized) {
+ CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
+ /* initialize on first use */
+ state->is_initialized = 1;
+ cx18_av_initialize(cx);
+ }
+
+ switch (cmd) {
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ return cx18_av_vbi(cx, cmd, arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return cx18_av_audio(cx, cmd, arg);
+
+ case VIDIOC_STREAMON:
+ CX18_DEBUG_INFO("enable output\n");
+ cx18_av_write(cx, 0x115, 0x8c);
+ cx18_av_write(cx, 0x116, 0x07);
+ break;
+
+ case VIDIOC_STREAMOFF:
+ CX18_DEBUG_INFO("disable output\n");
+ cx18_av_write(cx, 0x115, 0x00);
+ cx18_av_write(cx, 0x116, 0x00);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ log_video_status(cx);
+ log_audio_status(cx);
+ break;
+
+ case VIDIOC_G_CTRL:
+ return get_v4lctrl(cx, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return set_v4lctrl(cx, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = state->std;
+ break;
+
+ case VIDIOC_S_STD:
+ if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
+ return 0;
+ state->radio = 0;
+ state->std = *(v4l2_std_id *)arg;
+ return set_v4lstd(cx);
+
+ case AUDC_SET_RADIO:
+ state->radio = 1;
+ break;
+
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ route->input = state->vid_input;
+ route->output = 0;
+ break;
+
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ return set_input(cx, route->input, state->aud_input);
+
+ case VIDIOC_INT_G_AUDIO_ROUTING:
+ route->input = state->aud_input;
+ route->output = 0;
+ break;
+
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ return set_input(cx, state->vid_input, route->input);
+
+ case VIDIOC_S_FREQUENCY:
+ input_change(cx);
+ break;
+
+ case VIDIOC_G_TUNER:
+ {
+ u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
+ u8 mode;
+ int val = 0;
+
+ if (state->radio)
+ break;
+
+ vt->signal = vpres ? 0xffff : 0x0;
+
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+ mode = cx18_av_read(cx, 0x804);
+
+ /* get rxsubchans and audmode */
+ if ((mode & 0xf) == 1)
+ val |= V4L2_TUNER_SUB_STEREO;
+ else
+ val |= V4L2_TUNER_SUB_MONO;
+
+ if (mode == 2 || mode == 4)
+ val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+ if (mode & 0x10)
+ val |= V4L2_TUNER_SUB_SAP;
+
+ vt->rxsubchans = val;
+ vt->audmode = state->audmode;
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ if (state->radio)
+ break;
+
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ /* mono -> mono
+ stereo -> mono
+ bilingual -> lang1 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x04);
+ break;
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1/lang2 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x07);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang2 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x01);
+ break;
+ default:
+ return -EINVAL;
+ }
+ state->audmode = vt->audmode;
+ break;
+
+ case VIDIOC_G_FMT:
+ return get_v4lfmt(cx, (struct v4l2_format *)arg);
+
+ case VIDIOC_S_FMT:
+ return set_v4lfmt(cx, (struct v4l2_format *)arg);
+
+ case VIDIOC_INT_RESET:
+ cx18_av_initialize(cx);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+
+static void log_video_status(struct cx18 *cx)
+{
+ static const char *const fmt_strs[] = {
+ "0x0",
+ "NTSC-M", "NTSC-J", "NTSC-4.43",
+ "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+ "0x9", "0xA", "0xB",
+ "SECAM",
+ "0xD", "0xE", "0xF"
+ };
+
+ struct cx18_av_state *state = &cx->av_state;
+ u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
+ u8 gen_stat1 = cx18_av_read(cx, 0x40d);
+ u8 gen_stat2 = cx18_av_read(cx, 0x40e);
+ int vid_input = state->vid_input;
+
+ CX18_INFO("Video signal: %spresent\n",
+ (gen_stat2 & 0x20) ? "" : "not ");
+ CX18_INFO("Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ CX18_INFO("Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ if (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8) {
+ CX18_INFO("Specified video input: Composite %d\n",
+ vid_input - CX18_AV_COMPOSITE1 + 1);
+ } else {
+ CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ }
+
+ CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 download_ctl = cx18_av_read(cx, 0x803);
+ u8 mod_det_stat0 = cx18_av_read(cx, 0x805);
+ u8 mod_det_stat1 = cx18_av_read(cx, 0x804);
+ u8 audio_config = cx18_av_read(cx, 0x808);
+ u8 pref_mode = cx18_av_read(cx, 0x809);
+ u8 afc0 = cx18_av_read(cx, 0x80b);
+ u8 mute_ctl = cx18_av_read(cx, 0x8d3);
+ int aud_input = state->aud_input;
+ char *p;
+
+ switch (mod_det_stat0) {
+ case 0x00: p = "mono"; break;
+ case 0x01: p = "stereo"; break;
+ case 0x02: p = "dual"; break;
+ case 0x04: p = "tri"; break;
+ case 0x10: p = "mono with SAP"; break;
+ case 0x11: p = "stereo with SAP"; break;
+ case 0x12: p = "dual with SAP"; break;
+ case 0x14: p = "tri with SAP"; break;
+ case 0xfe: p = "forced mode"; break;
+ default: p = "not defined";
+ }
+ CX18_INFO("Detected audio mode: %s\n", p);
+
+ switch (mod_det_stat1) {
+ case 0x00: p = "BTSC"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+ case 0xff: p = "no detected audio standard"; break;
+ default: p = "not defined";
+ }
+ CX18_INFO("Detected audio standard: %s\n", p);
+ CX18_INFO("Audio muted: %s\n",
+ (mute_ctl & 0x2) ? "yes" : "no");
+ CX18_INFO("Audio microcontroller: %s\n",
+ (download_ctl & 0x10) ? "running" : "stopped");
+
+ switch (audio_config >> 4) {
+ case 0x00: p = "BTSC"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "FM radio"; break;
+ case 0x0f: p = "automatic detection"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio standard: %s\n", p);
+
+ if ((audio_config >> 4) < 0xF) {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+ case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+ case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+ case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+ case 0x04: p = "STEREO"; break;
+ case 0x05: p = "DUAL1 (AB)"; break;
+ case 0x06: p = "DUAL2 (AC) (FM)"; break;
+ case 0x07: p = "DUAL3 (BC) (FM)"; break;
+ case 0x08: p = "DUAL4 (AC) (AM)"; break;
+ case 0x09: p = "DUAL5 (BC) (AM)"; break;
+ case 0x0a: p = "SAP"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio mode: %s\n", p);
+ } else {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "BG"; break;
+ case 0x01: p = "DK1"; break;
+ case 0x02: p = "DK2"; break;
+ case 0x03: p = "DK3"; break;
+ case 0x04: p = "I"; break;
+ case 0x05: p = "L"; break;
+ case 0x06: p = "BTSC"; break;
+ case 0x07: p = "EIAJ"; break;
+ case 0x08: p = "A2-M"; break;
+ case 0x09: p = "FM Radio"; break;
+ case 0x0f: p = "automatic standard and mode detection"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio system: %s\n", p);
+ }
+
+ if (aud_input)
+ CX18_INFO("Specified audio input: Tuner (In%d)\n",
+ aud_input);
+ else
+ CX18_INFO("Specified audio input: External\n");
+
+ switch (pref_mode & 0xf) {
+ case 0: p = "mono/language A"; break;
+ case 1: p = "language B"; break;
+ case 2: p = "language C"; break;
+ case 3: p = "analog fallback"; break;
+ case 4: p = "stereo"; break;
+ case 5: p = "language AC"; break;
+ case 6: p = "language BC"; break;
+ case 7: p = "language AB"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Preferred audio mode: %s\n", p);
+
+ if ((audio_config & 0xf) == 0xf) {
+ switch ((afc0 >> 2) & 0x1) {
+ case 0: p = "system DK"; break;
+ case 1: p = "system L"; break;
+ }
+ CX18_INFO("Selected 65 MHz format: %s\n", p);
+
+ switch (afc0 & 0x3) {
+ case 0: p = "BTSC"; break;
+ case 1: p = "EIAJ"; break;
+ case 2: p = "A2-M"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Selected 45 MHz format: %s\n", p);
+ }
+}
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
new file mode 100644
index 000000000000..786901d72e9a
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -0,0 +1,318 @@
+/*
+ * cx18 ADEC header
+ *
+ * Derived from cx25840-core.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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.
+ */
+
+#ifndef _CX18_AV_CORE_H_
+#define _CX18_AV_CORE_H_
+
+struct cx18;
+
+enum cx18_av_video_input {
+ /* Composite video inputs In1-In8 */
+ CX18_AV_COMPOSITE1 = 1,
+ CX18_AV_COMPOSITE2,
+ CX18_AV_COMPOSITE3,
+ CX18_AV_COMPOSITE4,
+ CX18_AV_COMPOSITE5,
+ CX18_AV_COMPOSITE6,
+ CX18_AV_COMPOSITE7,
+ CX18_AV_COMPOSITE8,
+
+ /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ chroma input (In5-In8) */
+ CX18_AV_SVIDEO_LUMA1 = 0x10,
+ CX18_AV_SVIDEO_LUMA2 = 0x20,
+ CX18_AV_SVIDEO_LUMA3 = 0x30,
+ CX18_AV_SVIDEO_LUMA4 = 0x40,
+ CX18_AV_SVIDEO_CHROMA4 = 0x400,
+ CX18_AV_SVIDEO_CHROMA5 = 0x500,
+ CX18_AV_SVIDEO_CHROMA6 = 0x600,
+ CX18_AV_SVIDEO_CHROMA7 = 0x700,
+ CX18_AV_SVIDEO_CHROMA8 = 0x800,
+
+ /* S-Video aliases for common luma/chroma combinations */
+ CX18_AV_SVIDEO1 = 0x510,
+ CX18_AV_SVIDEO2 = 0x620,
+ CX18_AV_SVIDEO3 = 0x730,
+ CX18_AV_SVIDEO4 = 0x840,
+};
+
+enum cx18_av_audio_input {
+ /* Audio inputs: serial or In4-In8 */
+ CX18_AV_AUDIO_SERIAL,
+ CX18_AV_AUDIO4 = 4,
+ CX18_AV_AUDIO5,
+ CX18_AV_AUDIO6,
+ CX18_AV_AUDIO7,
+ CX18_AV_AUDIO8,
+};
+
+struct cx18_av_state {
+ int radio;
+ v4l2_std_id std;
+ enum cx18_av_video_input vid_input;
+ enum cx18_av_audio_input aud_input;
+ u32 audclk_freq;
+ int audmode;
+ int vbi_line_offset;
+ u32 id;
+ u32 rev;
+ int is_initialized;
+};
+
+
+/* Registers */
+#define CXADEC_CHIP_TYPE_TIGER 0x837
+#define CXADEC_CHIP_TYPE_MAKO 0x843
+
+#define CXADEC_HOST_REG1 0x000
+#define CXADEC_HOST_REG2 0x001
+
+#define CXADEC_CHIP_CTRL 0x100
+#define CXADEC_AFE_CTRL 0x104
+#define CXADEC_PLL_CTRL1 0x108
+#define CXADEC_VID_PLL_FRAC 0x10C
+#define CXADEC_AUX_PLL_FRAC 0x110
+#define CXADEC_PIN_CTRL1 0x114
+#define CXADEC_PIN_CTRL2 0x118
+#define CXADEC_PIN_CFG1 0x11C
+#define CXADEC_PIN_CFG2 0x120
+
+#define CXADEC_PIN_CFG3 0x124
+#define CXADEC_I2S_MCLK 0x127
+
+#define CXADEC_AUD_LOCK1 0x128
+#define CXADEC_AUD_LOCK2 0x12C
+#define CXADEC_POWER_CTRL 0x130
+#define CXADEC_AFE_DIAG_CTRL1 0x134
+#define CXADEC_AFE_DIAG_CTRL2 0x138
+#define CXADEC_AFE_DIAG_CTRL3 0x13C
+#define CXADEC_PLL_DIAG_CTRL 0x140
+#define CXADEC_TEST_CTRL1 0x144
+#define CXADEC_TEST_CTRL2 0x148
+#define CXADEC_BIST_STAT 0x14C
+#define CXADEC_DLL1_DIAG_CTRL 0x158
+#define CXADEC_DLL2_DIAG_CTRL 0x15C
+
+/* IR registers */
+#define CXADEC_IR_CTRL_REG 0x200
+#define CXADEC_IR_TXCLK_REG 0x204
+#define CXADEC_IR_RXCLK_REG 0x208
+#define CXADEC_IR_CDUTY_REG 0x20C
+#define CXADEC_IR_STAT_REG 0x210
+#define CXADEC_IR_IRQEN_REG 0x214
+#define CXADEC_IR_FILTER_REG 0x218
+#define CXADEC_IR_FIFO_REG 0x21C
+
+/* Video Registers */
+#define CXADEC_MODE_CTRL 0x400
+#define CXADEC_OUT_CTRL1 0x404
+#define CXADEC_OUT_CTRL2 0x408
+#define CXADEC_GEN_STAT 0x40C
+#define CXADEC_INT_STAT_MASK 0x410
+#define CXADEC_LUMA_CTRL 0x414
+
+#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414
+#define CXADEC_CONTRAST_CTRL_BYTE 0x415
+#define CXADEC_LUMA_CTRL_BYTE_3 0x416
+
+#define CXADEC_HSCALE_CTRL 0x418
+#define CXADEC_VSCALE_CTRL 0x41C
+
+#define CXADEC_CHROMA_CTRL 0x420
+
+#define CXADEC_USAT_CTRL_BYTE 0x420
+#define CXADEC_VSAT_CTRL_BYTE 0x421
+#define CXADEC_HUE_CTRL_BYTE 0x422
+
+#define CXADEC_VBI_LINE_CTRL1 0x424
+#define CXADEC_VBI_LINE_CTRL2 0x428
+#define CXADEC_VBI_LINE_CTRL3 0x42C
+#define CXADEC_VBI_LINE_CTRL4 0x430
+#define CXADEC_VBI_LINE_CTRL5 0x434
+#define CXADEC_VBI_FC_CFG 0x438
+#define CXADEC_VBI_MISC_CFG1 0x43C
+#define CXADEC_VBI_MISC_CFG2 0x440
+#define CXADEC_VBI_PAY1 0x444
+#define CXADEC_VBI_PAY2 0x448
+#define CXADEC_VBI_CUST1_CFG1 0x44C
+#define CXADEC_VBI_CUST1_CFG2 0x450
+#define CXADEC_VBI_CUST1_CFG3 0x454
+#define CXADEC_VBI_CUST2_CFG1 0x458
+#define CXADEC_VBI_CUST2_CFG2 0x45C
+#define CXADEC_VBI_CUST2_CFG3 0x460
+#define CXADEC_VBI_CUST3_CFG1 0x464
+#define CXADEC_VBI_CUST3_CFG2 0x468
+#define CXADEC_VBI_CUST3_CFG3 0x46C
+#define CXADEC_HORIZ_TIM_CTRL 0x470
+#define CXADEC_VERT_TIM_CTRL 0x474
+#define CXADEC_SRC_COMB_CFG 0x478
+#define CXADEC_CHROMA_VBIOFF_CFG 0x47C
+#define CXADEC_FIELD_COUNT 0x480
+#define CXADEC_MISC_TIM_CTRL 0x484
+#define CXADEC_DFE_CTRL1 0x488
+#define CXADEC_DFE_CTRL2 0x48C
+#define CXADEC_DFE_CTRL3 0x490
+#define CXADEC_PLL_CTRL2 0x494
+#define CXADEC_HTL_CTRL 0x498
+#define CXADEC_COMB_CTRL 0x49C
+#define CXADEC_CRUSH_CTRL 0x4A0
+#define CXADEC_SOFT_RST_CTRL 0x4A4
+#define CXADEC_MV_DT_CTRL2 0x4A8
+#define CXADEC_MV_DT_CTRL3 0x4AC
+#define CXADEC_MISC_DIAG_CTRL 0x4B8
+
+#define CXADEC_DL_CTL 0x800
+#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */
+#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */
+#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */
+#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */
+
+#define CXADEC_STD_DET_STATUS 0x804
+
+#define CXADEC_STD_DET_CTL 0x808
+#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */
+#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */
+
+#define CXADEC_DW8051_INT 0x80C
+#define CXADEC_GENERAL_CTL 0x810
+#define CXADEC_AAGC_CTL 0x814
+#define CXADEC_IF_SRC_CTL 0x818
+#define CXADEC_ANLOG_DEMOD_CTL 0x81C
+#define CXADEC_ROT_FREQ_CTL 0x820
+#define CXADEC_FM1_CTL 0x824
+#define CXADEC_PDF_CTL 0x828
+#define CXADEC_DFT1_CTL1 0x82C
+#define CXADEC_DFT1_CTL2 0x830
+#define CXADEC_DFT_STATUS 0x834
+#define CXADEC_DFT2_CTL1 0x838
+#define CXADEC_DFT2_CTL2 0x83C
+#define CXADEC_DFT2_STATUS 0x840
+#define CXADEC_DFT3_CTL1 0x844
+#define CXADEC_DFT3_CTL2 0x848
+#define CXADEC_DFT3_STATUS 0x84C
+#define CXADEC_DFT4_CTL1 0x850
+#define CXADEC_DFT4_CTL2 0x854
+#define CXADEC_DFT4_STATUS 0x858
+#define CXADEC_AM_MTS_DET 0x85C
+#define CXADEC_ANALOG_MUX_CTL 0x860
+#define CXADEC_DIG_PLL_CTL1 0x864
+#define CXADEC_DIG_PLL_CTL2 0x868
+#define CXADEC_DIG_PLL_CTL3 0x86C
+#define CXADEC_DIG_PLL_CTL4 0x870
+#define CXADEC_DIG_PLL_CTL5 0x874
+#define CXADEC_DEEMPH_GAIN_CTL 0x878
+#define CXADEC_DEEMPH_COEF1 0x87C
+#define CXADEC_DEEMPH_COEF2 0x880
+#define CXADEC_DBX1_CTL1 0x884
+#define CXADEC_DBX1_CTL2 0x888
+#define CXADEC_DBX1_STATUS 0x88C
+#define CXADEC_DBX2_CTL1 0x890
+#define CXADEC_DBX2_CTL2 0x894
+#define CXADEC_DBX2_STATUS 0x898
+#define CXADEC_AM_FM_DIFF 0x89C
+
+/* NICAM registers go here */
+#define CXADEC_NICAM_STATUS 0x8C8
+#define CXADEC_DEMATRIX_CTL 0x8CC
+
+#define CXADEC_PATH1_CTL1 0x8D0
+#define CXADEC_PATH1_VOL_CTL 0x8D4
+#define CXADEC_PATH1_EQ_CTL 0x8D8
+#define CXADEC_PATH1_SC_CTL 0x8DC
+
+#define CXADEC_PATH2_CTL1 0x8E0
+#define CXADEC_PATH2_VOL_CTL 0x8E4
+#define CXADEC_PATH2_EQ_CTL 0x8E8
+#define CXADEC_PATH2_SC_CTL 0x8EC
+
+#define CXADEC_SRC_CTL 0x8F0
+#define CXADEC_SRC_LF_COEF 0x8F4
+#define CXADEC_SRC1_CTL 0x8F8
+#define CXADEC_SRC2_CTL 0x8FC
+#define CXADEC_SRC3_CTL 0x900
+#define CXADEC_SRC4_CTL 0x904
+#define CXADEC_SRC5_CTL 0x908
+#define CXADEC_SRC6_CTL 0x90C
+
+#define CXADEC_BASEBAND_OUT_SEL 0x910
+#define CXADEC_I2S_IN_CTL 0x914
+#define CXADEC_I2S_OUT_CTL 0x918
+#define CXADEC_AC97_CTL 0x91C
+#define CXADEC_QAM_PDF 0x920
+#define CXADEC_QAM_CONST_DEC 0x924
+#define CXADEC_QAM_ROTATOR_FREQ 0x948
+
+/* Bit defintions / settings used in Mako Audio */
+#define CXADEC_PREF_MODE_MONO_LANGA 0
+#define CXADEC_PREF_MODE_MONO_LANGB 1
+#define CXADEC_PREF_MODE_MONO_LANGC 2
+#define CXADEC_PREF_MODE_FALLBACK 3
+#define CXADEC_PREF_MODE_STEREO 4
+#define CXADEC_PREF_MODE_DUAL_LANG_AC 5
+#define CXADEC_PREF_MODE_DUAL_LANG_BC 6
+#define CXADEC_PREF_MODE_DUAL_LANG_AB 7
+
+
+#define CXADEC_DETECT_STEREO 1
+#define CXADEC_DETECT_DUAL 2
+#define CXADEC_DETECT_TRI 4
+#define CXADEC_DETECT_SAP 0x10
+#define CXADEC_DETECT_NO_SIGNAL 0xFF
+
+#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2
+#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3
+#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */
+#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */
+#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6
+#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7
+#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */
+#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
+#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-core.c */
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+u8 cx18_av_read(struct cx18 *cx, u16 addr);
+u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-firmware.c */
+int cx18_av_loadfw(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-audio.c */
+int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg);
+void cx18_av_audio_set_path(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-vbi.c */
+void cx18_av_vbi_setup(struct cx18 *cx);
+int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
new file mode 100644
index 000000000000..526e142156cd
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -0,0 +1,120 @@
+/*
+ * cx18 ADEC firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 "cx18-driver.h"
+#include <linux/firmware.h>
+
+#define FWFILE "v4l-cx23418-dig.fw"
+
+int cx18_av_loadfw(struct cx18 *cx)
+{
+ const struct firmware *fw = NULL;
+ u32 size;
+ u32 v;
+ u8 *ptr;
+ int i;
+
+ if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
+ CX18_ERR("unable to open firmware %s\n", FWFILE);
+ return -EINVAL;
+ }
+
+ cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+ cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
+
+ /* Reset the Mako core (Register is undocumented.) */
+ cx18_av_write4(cx, 0x8100, 0x00010000);
+
+ /* Put the 8051 in reset and enable firmware upload */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+ ptr = fw->data;
+ size = fw->size;
+
+ for (i = 0; i < size; i++) {
+ u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
+ u32 value = 0;
+ int retries;
+
+ for (retries = 0; retries < 5; retries++) {
+ cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+ value = cx18_av_read4(cx, CXADEC_DL_CTL);
+ if ((value & 0x3F00) == (dl_control & 0x3F00))
+ break;
+ }
+ if (retries >= 5) {
+ CX18_ERR("unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
+ }
+ }
+
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
+
+ /* Output to the 416 */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
+
+ /* Audio input control 1 set to Sony mode */
+ /* Audio output input 2 is 0 for slave operation input */
+ /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
+
+ /* Audio output control 1 is set to Sony mode */
+ /* Audio output control 2 is set to 1 for master mode */
+ /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
+ are generated) */
+ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
+
+ /* set alt I2s master clock to /16 and enable alt divider i2s
+ passthrough */
+ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
+
+ cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6);
+ /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
+
+ /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
+ /* Register 0x09CC is defined by the Merlin firmware, and doesn't
+ have a name in the spec. */
+ cx18_av_write4(cx, 0x09CC, 1);
+
+#define CX18_AUDIO_ENABLE 0xc72014
+ v = read_reg(CX18_AUDIO_ENABLE);
+ /* If bit 11 is 1 */
+ if (v & 0x800)
+ write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */
+
+ /* Enable WW auto audio standard detection */
+ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
+ v |= 0xFF; /* Auto by default */
+ v |= 0x400; /* Stereo by default */
+ v |= 0x14000000;
+ cx18_av_write4(cx, CXADEC_STD_DET_CTL, v);
+
+ release_firmware(fw);
+
+ CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size);
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
new file mode 100644
index 000000000000..d09f1daf4ebf
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -0,0 +1,413 @@
+/*
+ * cx18 ADEC VBI functions
+ *
+ * Derived from cx25840-vbi.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 "cx18-driver.h"
+
+static int odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static int decode_vps(u8 *dst, u8 *p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+
+ u8 c, err = 0;
+ int i;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) |
+ ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+
+ return err & 0xf0;
+}
+
+void cx18_av_vbi_setup(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+ int hblank, hactive, burst, vblank, vactive, sc;
+ int vblank656, src_decimation;
+ int luma_lpf, uv_lpf, comb;
+ u32 pll_int, pll_frac, pll_post;
+
+ /* datasheet startup, step 8d */
+ if (std & ~V4L2_STD_NTSC)
+ cx18_av_write(cx, 0x49f, 0x11);
+ else
+ cx18_av_write(cx, 0x49f, 0x14);
+
+ if (std & V4L2_STD_625_50) {
+ hblank = 0x084;
+ hactive = 0x2d0;
+ burst = 0x5d;
+ vblank = 0x024;
+ vactive = 0x244;
+ vblank656 = 0x28;
+ src_decimation = 0x21f;
+
+ luma_lpf = 2;
+ if (std & V4L2_STD_SECAM) {
+ uv_lpf = 0;
+ comb = 0;
+ sc = 0x0a425f;
+ } else if (std == V4L2_STD_PAL_Nc) {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 556453;
+ } else {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 0x0a8263;
+ }
+ } else {
+ hactive = 720;
+ hblank = 122;
+ vactive = 487;
+ luma_lpf = 1;
+ uv_lpf = 1;
+
+ src_decimation = 0x21f;
+ if (std == V4L2_STD_PAL_60) {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ luma_lpf = 2;
+ comb = 0x20;
+ sc = 0x0a8263;
+ } else if (std == V4L2_STD_PAL_M) {
+ vblank = 20;
+ vblank656 = 24;
+ burst = 0x61;
+ comb = 0x20;
+
+ sc = 555452;
+ } else {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ comb = 0x66;
+ sc = 556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int = cx18_av_read(cx, 0x108);
+ pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+ pll_post = cx18_av_read(cx, 0x109);
+ CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int, pll_frac, pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+
+ pll >>= 25;
+ pll /= pll_post;
+ CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+ pll / 1000000, pll % 1000000);
+ CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+ pll / 8000000, (pll / 8) % 1000000);
+
+ fin = ((u64)src_decimation * pll) >> 12;
+ CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+ fin / 1000000, fin % 1000000);
+
+ fsc = (((u64)sc) * pll) >> 24L;
+ CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+ fsc / 1000000, fsc % 1000000);
+
+ CX18_DEBUG_INFO("hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx18_av_write(cx, 0x470, hblank);
+ cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+ (hactive << 4)));
+ cx18_av_write(cx, 0x472, hactive >> 4);
+
+ /* Sets burst gate delay */
+ cx18_av_write(cx, 0x473, burst);
+
+ /* Sets vertical blanking delay and active duration */
+ cx18_av_write(cx, 0x474, vblank);
+ cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+ (vactive << 4)));
+ cx18_av_write(cx, 0x476, vactive >> 4);
+ cx18_av_write(cx, 0x477, vblank656);
+
+ /* Sets src decimation rate */
+ cx18_av_write(cx, 0x478, 0xff & src_decimation);
+ cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+ /* Sets Luma and UV Low pass filters */
+ cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+ /* Enables comb filters */
+ cx18_av_write(cx, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx18_av_write(cx, 0x47c, sc);
+ cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+ cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx18_av_write(cx, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
+ cx18_av_write(cx, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
+ }
+}
+
+int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+
+ switch (cmd) {
+ case VIDIOC_G_FMT:
+ {
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+ V4L2_SLICED_CAPTION_525, /* 6 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ 0, 0, 0, 0
+ };
+ int is_pal = !(state->std & V4L2_STD_525_60);
+ int i;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
+ /* we're done if raw VBI is active */
+ if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
+ break;
+
+ if (is_pal) {
+ for (i = 7; i <= 23; i++) {
+ u8 v = cx18_av_read(cx, 0x424 + i - 7);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |= svbi->service_lines[0][i] |
+ svbi->service_lines[1][i];
+ }
+ } else {
+ for (i = 10; i <= 21; i++) {
+ u8 v = cx18_av_read(cx, 0x424 + i - 10);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |= svbi->service_lines[0][i] |
+ svbi->service_lines[1][i];
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ int is_pal = !(state->std & V4L2_STD_525_60);
+ int vbi_offset = is_pal ? 1 : 0;
+ int i, x;
+ u8 lcr[24];
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set == 0) {
+ /* raw VBI */
+ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup VBI */
+ cx18_av_vbi_setup(cx);
+
+ /* VBI Offset */
+ cx18_av_write(cx, 0x47f, vbi_offset);
+ cx18_av_write(cx, 0x404, 0x2e);
+ break;
+ }
+
+ for (x = 0; x <= 23; x++)
+ lcr[x] = 0x00;
+
+ /* Setup VBI */
+ cx18_av_vbi_setup(cx);
+
+ /* Sliced VBI */
+ cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
+ cx18_av_write(cx, 0x406, 0x13);
+ cx18_av_write(cx, 0x47f, vbi_offset);
+
+ if (is_pal) {
+ for (i = 0; i <= 6; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ } else {
+ for (i = 0; i <= 9; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+
+ for (i = 22; i <= 23; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ }
+
+ for (i = 7; i <= 23; i++) {
+ for (x = 0; x <= 1; x++) {
+ switch (svbi->service_lines[1-x][i]) {
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 6 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 9 << (4 * x);
+ break;
+ }
+ }
+ }
+
+ if (is_pal) {
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+ cx18_av_write(cx, i, lcr[6 + x]);
+ } else {
+ for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+ cx18_av_write(cx, i, lcr[9 + x]);
+ for (i = 0x431; i <= 0x434; i++)
+ cx18_av_write(cx, i, 0);
+ }
+
+ cx18_av_write(cx, 0x43c, 0x16);
+ cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
+ break;
+ }
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ {
+ struct v4l2_decode_vbi_line *vbi = arg;
+ u8 *p = vbi->p;
+ int id1, id2, l, err = 0;
+
+ if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+ (p[3] != 0x55 && p[3] != 0x91)) {
+ vbi->line = vbi->type = 0;
+ break;
+ }
+
+ p += 4;
+ id1 = p[-1];
+ id2 = p[0] & 0xf;
+ l = p[2] & 0x3f;
+ l += state->vbi_line_offset;
+ p += 4;
+
+ switch (id2) {
+ case 1:
+ id2 = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ id2 = V4L2_SLICED_WSS_625;
+ break;
+ case 6:
+ id2 = V4L2_SLICED_CAPTION_525;
+ err = !odd_parity(p[0]) || !odd_parity(p[1]);
+ break;
+ case 9:
+ id2 = V4L2_SLICED_VPS;
+ if (decode_vps(p, p) != 0)
+ err = 1;
+ break;
+ default:
+ id2 = 0;
+ err = 1;
+ break;
+ }
+
+ vbi->type = err ? 0 : id2;
+ vbi->line = err ? 0 : l;
+ vbi->is_second_field = err ? 0 : (id1 == 0x55);
+ vbi->p = p;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
new file mode 100644
index 000000000000..553adbf2cd44
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -0,0 +1,280 @@
+/*
+ * cx18 functions to query card hardware
+ *
+ * Derived from ivtv-cards.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include <media/cs5345.h>
+
+/********************** card configuration *******************************/
+
+/* usual i2c tuner addresses to probe */
+static struct cx18_card_tuner_i2c cx18_i2c_std = {
+ .radio = { I2C_CLIENT_END },
+ .demod = { 0x43, I2C_CLIENT_END },
+ .tv = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+ This keeps the PCI ID database up to date. Note that the entries
+ must be added under vendor 0x4444 (Conexant) as subsystem IDs.
+ New vendor IDs should still be added to the vendor ID list. */
+
+/* Hauppauge HVR-1600 cards */
+
+/* Note: for Hauppauge cards the tveeprom information is used instead
+ of PCI IDs */
+static const struct cx18_card cx18_card_hvr1600_esmt = {
+ .type = CX18_CARD_HVR_1600_ESMT,
+ .name = "Hauppauge HVR-1600",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_CS5345,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+ CX18_HW_CS5345 | CX18_HW_DVB,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ { CX18_CARD_INPUT_LINE_IN2,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .ddr = {
+ /* ESMT M13S128324A-5B memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x44220e82,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .gpio_init.initial_value = 0x3001,
+ .gpio_init.direction = 0x3001,
+ .i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card cx18_card_hvr1600_samsung = {
+ .type = CX18_CARD_HVR_1600_SAMSUNG,
+ .name = "Hauppauge HVR-1600 (Preproduction)",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_CS5345,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+ CX18_HW_CS5345 | CX18_HW_DVB,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ { CX18_CARD_INPUT_LINE_IN2,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .ddr = {
+ /* Samsung K4D263238G-VC33 memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x23230b73,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .gpio_init.initial_value = 0x3001,
+ .gpio_init.direction = 0x3001,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Compro VideoMate H900: not working at the moment! */
+
+static const struct cx18_card_pci_info cx18_pci_h900[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_h900 = {
+ .type = CX18_CARD_COMPRO_H900,
+ .name = "Compro VideoMate H900",
+ .comment = "DVB & VBI are not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_all = CX18_HW_TUNER,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX23418_SVIDEO_LUMA3 | CX23418_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, 0 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, 0 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .ddr = {
+ /* EtronTech EM6A9160TS-5G memory */
+ .chip_config = 0x50003,
+ .refresh = 0x753,
+ .timing1 = 0x24330e84,
+ .timing2 = 0x1f,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .xceive_pin = 15,
+ .pci_list = cx18_pci_h900,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPC718: not working at the moment! */
+
+static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_mpc718 = {
+ .type = CX18_CARD_YUAN_MPC718,
+ .name = "Yuan MPC718",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_all = CX18_HW_TUNER,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, 0 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, 0 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .tuners = {
+ /* XC3028 tuner */
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .ddr = {
+ /* Probably Samsung K4D263238G-VC33 memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x23230b73,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .xceive_pin = 15,
+ .pci_list = cx18_pci_mpc718,
+ .i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card *cx18_card_list[] = {
+ &cx18_card_hvr1600_esmt,
+ &cx18_card_hvr1600_samsung,
+ &cx18_card_h900,
+ &cx18_card_mpc718,
+};
+
+const struct cx18_card *cx18_get_card(u16 index)
+{
+ if (index >= ARRAY_SIZE(cx18_card_list))
+ return NULL;
+ return cx18_card_list[index];
+}
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
+{
+ const struct cx18_card_video_input *card_input =
+ cx->card->video_inputs + index;
+ static const char * const input_strs[] = {
+ "Tuner 1",
+ "S-Video 1",
+ "S-Video 2",
+ "Composite 1",
+ "Composite 2",
+ "Composite 3"
+ };
+
+ memset(input, 0, sizeof(*input));
+ if (index >= cx->nof_inputs)
+ return -EINVAL;
+ input->index = index;
+ strlcpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
+ input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ?
+ V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
+ input->audioset = (1 << cx->nof_audio_inputs) - 1;
+ input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
+ cx->tuner_std : V4L2_STD_ALL;
+ return 0;
+}
+
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio)
+{
+ const struct cx18_card_audio_input *aud_input =
+ cx->card->audio_inputs + index;
+ static const char * const input_strs[] = {
+ "Tuner 1",
+ "Line In 1",
+ "Line In 2"
+ };
+
+ memset(audio, 0, sizeof(*audio));
+ if (index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
+ audio->index = index;
+ audio->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
new file mode 100644
index 000000000000..bccb67f0db16
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -0,0 +1,171 @@
+/*
+ * cx18 functions to query card hardware
+ *
+ * Derived from ivtv-cards.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+/* hardware flags */
+#define CX18_HW_TUNER (1 << 0)
+#define CX18_HW_TVEEPROM (1 << 1)
+#define CX18_HW_CS5345 (1 << 2)
+#define CX18_HW_GPIO (1 << 3)
+#define CX18_HW_CX23418 (1 << 4)
+#define CX18_HW_DVB (1 << 5)
+
+/* video inputs */
+#define CX18_CARD_INPUT_VID_TUNER 1
+#define CX18_CARD_INPUT_SVIDEO1 2
+#define CX18_CARD_INPUT_SVIDEO2 3
+#define CX18_CARD_INPUT_COMPOSITE1 4
+#define CX18_CARD_INPUT_COMPOSITE2 5
+#define CX18_CARD_INPUT_COMPOSITE3 6
+
+enum cx34180_video_input {
+ /* Composite video inputs In1-In8 */
+ CX23418_COMPOSITE1 = 1,
+ CX23418_COMPOSITE2,
+ CX23418_COMPOSITE3,
+ CX23418_COMPOSITE4,
+ CX23418_COMPOSITE5,
+ CX23418_COMPOSITE6,
+ CX23418_COMPOSITE7,
+ CX23418_COMPOSITE8,
+
+ /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ chroma input (In5-In8) */
+ CX23418_SVIDEO_LUMA1 = 0x10,
+ CX23418_SVIDEO_LUMA2 = 0x20,
+ CX23418_SVIDEO_LUMA3 = 0x30,
+ CX23418_SVIDEO_LUMA4 = 0x40,
+ CX23418_SVIDEO_CHROMA4 = 0x400,
+ CX23418_SVIDEO_CHROMA5 = 0x500,
+ CX23418_SVIDEO_CHROMA6 = 0x600,
+ CX23418_SVIDEO_CHROMA7 = 0x700,
+ CX23418_SVIDEO_CHROMA8 = 0x800,
+
+ /* S-Video aliases for common luma/chroma combinations */
+ CX23418_SVIDEO1 = 0x510,
+ CX23418_SVIDEO2 = 0x620,
+ CX23418_SVIDEO3 = 0x730,
+ CX23418_SVIDEO4 = 0x840,
+};
+
+/* audio inputs */
+#define CX18_CARD_INPUT_AUD_TUNER 1
+#define CX18_CARD_INPUT_LINE_IN1 2
+#define CX18_CARD_INPUT_LINE_IN2 3
+
+#define CX18_CARD_MAX_VIDEO_INPUTS 6
+#define CX18_CARD_MAX_AUDIO_INPUTS 3
+#define CX18_CARD_MAX_TUNERS 2
+
+enum cx23418_audio_input {
+ /* Audio inputs: serial or In4-In8 */
+ CX23418_AUDIO_SERIAL,
+ CX23418_AUDIO4 = 4,
+ CX23418_AUDIO5,
+ CX23418_AUDIO6,
+ CX23418_AUDIO7,
+ CX23418_AUDIO8,
+};
+
+/* V4L2 capability aliases */
+#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
+/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+
+struct cx18_card_video_input {
+ u8 video_type; /* video input type */
+ u8 audio_index; /* index in cx18_card_audio_input array */
+ u16 video_input; /* hardware video input */
+};
+
+struct cx18_card_audio_input {
+ u8 audio_type; /* audio input type */
+ u32 audio_input; /* hardware audio input */
+ u16 muxer_input; /* hardware muxer input for boards with a
+ multiplexer chip */
+};
+
+struct cx18_card_pci_info {
+ u16 device;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+};
+
+/* GPIO definitions */
+
+/* The mask is the set of bits used by the operation */
+
+struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
+ u32 direction; /* DIR setting. Leave to 0 if no init is needed */
+ u32 initial_value;
+};
+
+struct cx18_card_tuner {
+ v4l2_std_id std; /* standard for which the tuner is suitable */
+ int tuner; /* tuner ID (from tuner.h) */
+};
+
+struct cx18_card_tuner_i2c {
+ unsigned short radio[2];/* radio tuner i2c address to probe */
+ unsigned short demod[2];/* demodulator i2c address to probe */
+ unsigned short tv[4]; /* tv tuner i2c addresses to probe */
+};
+
+struct cx18_ddr { /* DDR config data */
+ u32 chip_config;
+ u32 refresh;
+ u32 timing1;
+ u32 timing2;
+ u32 tune_lane;
+ u32 initial_emrs;
+};
+
+/* for card information/parameters */
+struct cx18_card {
+ int type;
+ char *name;
+ char *comment;
+ u32 v4l2_capabilities;
+ u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only
+ 1 dev allowed) */
+ u32 hw_muxer; /* hardware used to multiplex audio input */
+ u32 hw_all; /* all hardware used by the board */
+ struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
+ struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS];
+ struct cx18_card_audio_input radio_input;
+
+ /* GPIO card-specific settings */
+ u8 xceive_pin; /* XCeive tuner GPIO reset pin */
+ struct cx18_gpio_init gpio_init;
+
+ struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
+ struct cx18_card_tuner_i2c *i2c;
+
+ struct cx18_ddr ddr;
+
+ /* list of device and subsystem vendor/devices that
+ correspond to this card type. */
+ const struct cx18_card_pci_info *pci_list;
+};
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input);
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input);
+const struct cx18_card *cx18_get_card(u16 index);
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
new file mode 100644
index 000000000000..2bdac5ebbb0d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -0,0 +1,306 @@
+/*
+ * cx18 ioctl control functions
+ *
+ * Derived from ivtv-controls.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-av-core.h"
+#include "cx18-cards.h"
+#include "cx18-ioctl.h"
+#include "cx18-audio.h"
+#include "cx18-i2c.h"
+#include "cx18-mailbox.h"
+#include "cx18-controls.h"
+
+static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+ V4L2_CID_AUDIO_BALANCE,
+ V4L2_CID_AUDIO_BASS,
+ V4L2_CID_AUDIO_TREBLE,
+ V4L2_CID_AUDIO_MUTE,
+ V4L2_CID_AUDIO_LOUDNESS,
+ 0
+};
+
+static const u32 *ctrl_classes[] = {
+ user_ctrls,
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+{
+ const char *name;
+
+ CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
+
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ switch (qctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ default:
+ if (cx2341x_ctrl_query(&cx->params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
+ qctrl->name[sizeof(qctrl->name) - 1] = 0;
+ return 0;
+}
+
+static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx18_queryctrl(cx, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
+ s32 v = vctrl->value;
+
+ CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+
+ switch (vctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+
+ default:
+ CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
+ CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
+
+ switch (vctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+ default:
+ CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
+{
+ if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
+ return -EINVAL;
+ if (atomic_read(&cx->capturing) > 0)
+ return -EBUSY;
+
+ /* First try to allocate sliced VBI buffers if needed. */
+ if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
+ int i;
+
+ for (i = 0; i < CX18_VBI_FRAMES; i++) {
+ /* Yuck, hardcoded. Needs to be a define */
+ cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+ if (cx->vbi.sliced_mpeg_data[i] == NULL) {
+ while (--i >= 0) {
+ kfree(cx->vbi.sliced_mpeg_data[i]);
+ cx->vbi.sliced_mpeg_data[i] = NULL;
+ }
+ return -ENOMEM;
+ }
+ }
+ }
+
+ cx->vbi.insert_mpeg = fmt;
+
+ if (cx->vbi.insert_mpeg == 0)
+ return 0;
+ /* Need sliced data for mpeg insertion */
+ if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
+ if (cx->is_60hz)
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+ else
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+ cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
+ }
+ return 0;
+}
+
+int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_control ctrl;
+
+ switch (cmd) {
+ case VIDIOC_QUERYMENU:
+ CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
+ return cx18_querymenu(cx, arg);
+
+ case VIDIOC_QUERYCTRL:
+ return cx18_queryctrl(cx, arg);
+
+ case VIDIOC_S_CTRL:
+ return cx18_s_ctrl(cx, arg);
+
+ case VIDIOC_G_CTRL:
+ return cx18_g_ctrl(cx, arg);
+
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_s_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ struct cx2341x_mpeg_params p = cx->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd);
+
+ if (err)
+ return err;
+
+ if (p.video_encoding != cx->params.video_encoding) {
+ int is_mpeg1 = p.video_encoding ==
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_format fmt;
+
+ /* fix videodecoder resolution */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = cx->params.height;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+ }
+ err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+ if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ cx->params = p;
+ cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+ cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+ return err;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_g_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
+ return -EINVAL;
+ }
+
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params,
+ atomic_read(&cx->capturing), arg, cmd);
+ return -EINVAL;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h
new file mode 100644
index 000000000000..6e985cf422a0
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-controls.h
@@ -0,0 +1,24 @@
+/*
+ * cx18 ioctl control functions
+ *
+ * Derived from ivtv-controls.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
new file mode 100644
index 000000000000..0dd4e0529970
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -0,0 +1,964 @@
+/*
+ * cx18 driver initialization and card probing
+ *
+ * Derived from ivtv-driver.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include "cx18-irq.h"
+#include "cx18-gpio.h"
+#include "cx18-firmware.h"
+#include "cx18-streams.h"
+#include "cx18-av-core.h"
+#include "cx18-scb.h"
+#include "cx18-mailbox.h"
+#include "cx18-ioctl.h"
+#include "tuner-xc2028.h"
+
+#include <media/tveeprom.h>
+
+
+/* var to keep track of the number of array elements in use */
+int cx18_cards_active;
+
+/* If you have already X v4l cards, then set this to X. This way
+ the device numbers stay matched. Example: you have a WinTV card
+ without radio and a Compro H900 with. Normally this would give a
+ video1 device together with a radio0 device for the Compro. By
+ setting this to 1 you ensure that radio0 is now also radio1. */
+int cx18_first_minor;
+
+/* Master variable for all cx18 info */
+struct cx18 *cx18_cards[CX18_MAX_CARDS];
+
+/* Protects cx18_cards_active */
+DEFINE_SPINLOCK(cx18_cards_lock);
+
+/* add your revision and whatnot here */
+static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+ {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+
+/* Parameter declarations */
+static int cardtype[CX18_MAX_CARDS];
+static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static int cardtype_c = 1;
+static int tuner_c = 1;
+static int radio_c = 1;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+
+static int cx18_pci_latency = 1;
+
+int cx18_debug;
+
+module_param_array(tuner, int, &tuner_c, 0644);
+module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug, cx18_debug, int, 0644);
+module_param(cx18_pci_latency, int, 0644);
+module_param(cx18_first_minor, int, 0644);
+
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_ts_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+ "\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+ "Enable or disable the radio. Use only if autodetection\n"
+ "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+ "Only use this option if your card is not detected properly.\n"
+ "\t\tSpecify card type:\n"
+ "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
+ "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
+ "\t\t\t 3 = Compro VideoMate H900\n"
+ "\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 0 = Autodetect (default)\n"
+ "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: 0\n"
+ "\t\t\t 1/0x0001: warning\n"
+ "\t\t\t 2/0x0002: info\n"
+ "\t\t\t 4/0x0004: mailbox\n"
+ "\t\t\t 8/0x0008: dma\n"
+ "\t\t\t 16/0x0010: ioctl\n"
+ "\t\t\t 32/0x0020: file\n"
+ "\t\t\t 64/0x0040: i2c\n"
+ "\t\t\t128/0x0080: irq\n"
+ "\t\t\t256/0x0100: high volume\n");
+MODULE_PARM_DESC(cx18_pci_latency,
+ "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+ "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(enc_mpg_buffers,
+ "Encoder MPG Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_ts_buffers,
+ "Encoder TS Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_buffers,
+ "Encoder YUV Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_buffers,
+ "Encoder VBI Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_buffers,
+ "Encoder PCM buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+
+MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card");
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("CX23418 driver");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+/* Generic utility functions */
+int cx18_msleep_timeout(unsigned int msecs, int intr)
+{
+ int timeout = msecs_to_jiffies(msecs);
+ int sig;
+
+ do {
+ set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ sig = intr ? signal_pending(current) : 0;
+ } while (!sig && timeout);
+ return sig;
+}
+
+/* Release ioremapped memory */
+static void cx18_iounmap(struct cx18 *cx)
+{
+ if (cx == NULL)
+ return;
+
+ /* Release io memory */
+ if (cx->enc_mem != NULL) {
+ CX18_DEBUG_INFO("releasing enc_mem\n");
+ iounmap(cx->enc_mem);
+ cx->enc_mem = NULL;
+ }
+}
+
+/* Hauppauge card? get values from tveeprom */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
+{
+ u8 eedata[256];
+
+ cx->i2c_client[0].addr = 0xA0 >> 1;
+ tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata));
+ tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata);
+}
+
+static void cx18_process_eeprom(struct cx18 *cx)
+{
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+
+ /* Many thanks to Steven Toth from Hauppauge for providing the
+ model numbers */
+ /* Note: the Samsung memory models cannot be reliably determined
+ from the model number. Use the cardtype module option if you
+ have one of these preproduction models. */
+ switch (tv.model) {
+ case 74000 ... 74999:
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ case 0:
+ CX18_ERR("Invalid EEPROM\n");
+ return;
+ default:
+ CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model);
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ }
+
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+
+ CX18_INFO("Autodetected %s\n", cx->card_name);
+
+ if (tv.tuner_type == TUNER_ABSENT)
+ CX18_ERR("tveeprom cannot autodetect tuner!");
+
+ if (cx->options.tuner == -1)
+ cx->options.tuner = tv.tuner_type;
+ if (cx->options.radio == -1)
+ cx->options.radio = (tv.has_radio != 0);
+
+ if (cx->std != 0)
+ /* user specified tuner standard */
+ return;
+
+ /* autodetect tuner standard */
+ if (tv.tuner_formats & V4L2_STD_PAL) {
+ CX18_DEBUG_INFO("PAL tuner detected\n");
+ cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ } else if (tv.tuner_formats & V4L2_STD_NTSC) {
+ CX18_DEBUG_INFO("NTSC tuner detected\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ } else if (tv.tuner_formats & V4L2_STD_SECAM) {
+ CX18_DEBUG_INFO("SECAM tuner detected\n");
+ cx->std |= V4L2_STD_SECAM_L;
+ } else {
+ CX18_INFO("No tuner detected, default to NTSC-M\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ }
+}
+
+static v4l2_std_id cx18_parse_std(struct cx18 *cx)
+{
+ switch (pal[0]) {
+ case '6':
+ return V4L2_STD_PAL_60;
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ return V4L2_STD_PAL_BG;
+ case 'h':
+ case 'H':
+ return V4L2_STD_PAL_H;
+ case 'n':
+ case 'N':
+ if (pal[1] == 'c' || pal[1] == 'C')
+ return V4L2_STD_PAL_Nc;
+ return V4L2_STD_PAL_N;
+ case 'i':
+ case 'I':
+ return V4L2_STD_PAL_I;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_PAL_DK;
+ case 'M':
+ case 'm':
+ return V4L2_STD_PAL_M;
+ case '-':
+ break;
+ default:
+ CX18_WARN("pal= argument not recognised\n");
+ return 0;
+ }
+
+ switch (secam[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_SECAM_DK;
+ case 'l':
+ case 'L':
+ if (secam[1] == 'C' || secam[1] == 'c')
+ return V4L2_STD_SECAM_LC;
+ return V4L2_STD_SECAM_L;
+ case '-':
+ break;
+ default:
+ CX18_WARN("secam= argument not recognised\n");
+ return 0;
+ }
+
+ switch (ntsc[0]) {
+ case 'm':
+ case 'M':
+ return V4L2_STD_NTSC_M;
+ case 'j':
+ case 'J':
+ return V4L2_STD_NTSC_M_JP;
+ case 'k':
+ case 'K':
+ return V4L2_STD_NTSC_M_KR;
+ case '-':
+ break;
+ default:
+ CX18_WARN("ntsc= argument not recognised\n");
+ return 0;
+ }
+
+ /* no match found */
+ return 0;
+}
+
+static void cx18_process_options(struct cx18 *cx)
+{
+ int i, j;
+
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ cx->options.cardtype = cardtype[cx->num];
+ cx->options.tuner = tuner[cx->num];
+ cx->options.radio = radio[cx->num];
+
+ cx->std = cx18_parse_std(cx);
+ if (cx->options.cardtype == -1) {
+ CX18_INFO("Ignore card\n");
+ return;
+ }
+ cx->card = cx18_get_card(cx->options.cardtype - 1);
+ if (cx->card)
+ CX18_INFO("User specified %s card\n", cx->card->name);
+ else if (cx->options.cardtype != 0)
+ CX18_ERR("Unknown user specified type, trying to autodetect card\n");
+ if (cx->card == NULL) {
+ if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_INFO("Autodetected Hauppauge card\n");
+ }
+ }
+ if (cx->card == NULL) {
+ for (i = 0; (cx->card = cx18_get_card(i)); i++) {
+ if (cx->card->pci_list == NULL)
+ continue;
+ for (j = 0; cx->card->pci_list[j].device; j++) {
+ if (cx->dev->device !=
+ cx->card->pci_list[j].device)
+ continue;
+ if (cx->dev->subsystem_vendor !=
+ cx->card->pci_list[j].subsystem_vendor)
+ continue;
+ if (cx->dev->subsystem_device !=
+ cx->card->pci_list[j].subsystem_device)
+ continue;
+ CX18_INFO("Autodetected %s card\n", cx->card->name);
+ goto done;
+ }
+ }
+ }
+done:
+
+ if (cx->card == NULL) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_ERR("Unknown card: vendor/device: %04x/%04x\n",
+ cx->dev->vendor, cx->dev->device);
+ CX18_ERR(" subsystem vendor/device: %04x/%04x\n",
+ cx->dev->subsystem_vendor, cx->dev->subsystem_device);
+ CX18_ERR("Defaulting to %s card\n", cx->card->name);
+ CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+ CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+ CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
+ }
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+}
+
+/* Precondition: the cx18 structure has been memset to 0. Only
+ the dev and num fields have been filled in.
+ No assumptions on the card type may be made here (see cx18_init_struct2
+ for that).
+ */
+static int __devinit cx18_init_struct1(struct cx18 *cx)
+{
+ cx->base_addr = pci_resource_start(cx->dev, 0);
+
+ mutex_init(&cx->serialize_lock);
+ mutex_init(&cx->i2c_bus_lock[0]);
+ mutex_init(&cx->i2c_bus_lock[1]);
+
+ spin_lock_init(&cx->lock);
+ spin_lock_init(&cx->dma_reg_lock);
+
+ /* start counting open_id at 1 */
+ cx->open_id = 1;
+
+ /* Initial settings */
+ cx2341x_fill_defaults(&cx->params);
+ cx->temporal_strength = cx->params.video_temporal_filter;
+ cx->spatial_strength = cx->params.video_spatial_filter;
+ cx->filter_mode = cx->params.video_spatial_filter_mode |
+ (cx->params.video_temporal_filter_mode << 1) |
+ (cx->params.video_median_filter_type << 2);
+ cx->params.port = CX2341X_PORT_MEMORY;
+ cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+ init_waitqueue_head(&cx->cap_w);
+ init_waitqueue_head(&cx->mb_apu_waitq);
+ init_waitqueue_head(&cx->mb_cpu_waitq);
+ init_waitqueue_head(&cx->mb_epu_waitq);
+ init_waitqueue_head(&cx->mb_hpu_waitq);
+ init_waitqueue_head(&cx->dma_waitq);
+
+ /* VBI */
+ cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
+ cx->vbi.raw_size = 1456;
+ cx->vbi.raw_decoder_line_size = 1456;
+ cx->vbi.raw_decoder_sav_odd_field = 0x20;
+ cx->vbi.raw_decoder_sav_even_field = 0x60;
+ cx->vbi.sliced_decoder_line_size = 272;
+ cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
+ cx->vbi.sliced_decoder_sav_even_field = 0xF0;
+ return 0;
+}
+
+/* Second initialization part. Here the card type has been
+ autodetected. */
+static void __devinit cx18_init_struct2(struct cx18 *cx)
+{
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
+ if (cx->card->video_inputs[i].video_type == 0)
+ break;
+ cx->nof_inputs = i;
+ for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
+ if (cx->card->audio_inputs[i].audio_type == 0)
+ break;
+ cx->nof_audio_inputs = i;
+
+ /* Find tuner input */
+ for (i = 0; i < cx->nof_inputs; i++) {
+ if (cx->card->video_inputs[i].video_type ==
+ CX18_CARD_INPUT_VID_TUNER)
+ break;
+ }
+ if (i == cx->nof_inputs)
+ i = 0;
+ cx->active_input = i;
+ cx->audio_input = cx->card->video_inputs[i].audio_index;
+ cx->av_state.vid_input = CX18_AV_COMPOSITE7;
+ cx->av_state.aud_input = CX18_AV_AUDIO8;
+ cx->av_state.audclk_freq = 48000;
+ cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+ cx->av_state.vbi_line_offset = 8;
+}
+
+static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
+ const struct pci_device_id *pci_id)
+{
+ u16 cmd;
+ unsigned char pci_latency;
+
+ CX18_DEBUG_INFO("Enabling pci device\n");
+
+ if (pci_enable_device(dev)) {
+ CX18_ERR("Can't enable device %d!\n", cx->num);
+ return -EIO;
+ }
+ if (pci_set_dma_mask(dev, 0xffffffff)) {
+ CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
+ return -EIO;
+ }
+ if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
+ CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
+ return -EIO;
+ }
+
+ /* Check for bus mastering */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+
+ if (pci_latency < 64 && cx18_pci_latency) {
+ CX18_INFO("Unreasonably low latency timer, "
+ "setting to 64 (was %d)\n", pci_latency);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+ }
+ /* This config space value relates to DMA latencies. The
+ default value 0x8080 is too low however and will lead
+ to DMA errors. 0xffff is the max value which solves
+ these problems. */
+ pci_write_config_dword(dev, 0x40, 0xffff);
+
+ CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
+ "irq: %d, latency: %d, memory: 0x%lx\n",
+ cx->dev->device, cx->card_rev, dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);
+
+ return 0;
+}
+
+#ifdef MODULE
+static u32 cx18_request_module(struct cx18 *cx, u32 hw,
+ const char *name, u32 id)
+{
+ if ((hw & id) == 0)
+ return hw;
+ if (request_module(name) != 0) {
+ CX18_ERR("Failed to load module %s\n", name);
+ return hw & ~id;
+ }
+ CX18_DEBUG_INFO("Loaded module %s\n", name);
+ return hw;
+}
+#endif
+
+static void cx18_load_and_init_modules(struct cx18 *cx)
+{
+ u32 hw = cx->card->hw_all;
+ int i;
+
+#ifdef MODULE
+ /* load modules */
+#ifndef CONFIG_MEDIA_TUNER
+ hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
+#endif
+#ifndef CONFIG_VIDEO_CS5345
+ hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
+#endif
+#endif
+
+ /* check which i2c devices are actually found */
+ for (i = 0; i < 32; i++) {
+ u32 device = 1 << i;
+
+ if (!(device & hw))
+ continue;
+ if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM ||
+ device == CX18_HW_CX23418 || device == CX18_HW_DVB) {
+ /* These 'devices' do not use i2c probing */
+ cx->hw_flags |= device;
+ continue;
+ }
+ cx18_i2c_register(cx, i);
+ if (cx18_i2c_hw_addr(cx, device) > 0)
+ cx->hw_flags |= device;
+ }
+
+ hw = cx->hw_flags;
+}
+
+static int __devinit cx18_probe(struct pci_dev *dev,
+ const struct pci_device_id *pci_id)
+{
+ int retval = 0;
+ int vbi_buf_size;
+ u32 devtype;
+ struct cx18 *cx;
+
+ spin_lock(&cx18_cards_lock);
+
+ /* Make sure we've got a place for this card */
+ if (cx18_cards_active == CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n",
+ cx18_cards_active);
+ spin_unlock(&cx18_cards_lock);
+ return -ENOMEM;
+ }
+
+ cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
+ if (!cx) {
+ spin_unlock(&cx18_cards_lock);
+ return -ENOMEM;
+ }
+ cx18_cards[cx18_cards_active] = cx;
+ cx->dev = dev;
+ cx->num = cx18_cards_active++;
+ snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
+ CX18_INFO("Initializing card #%d\n", cx->num);
+
+ spin_unlock(&cx18_cards_lock);
+
+ cx18_process_options(cx);
+ if (cx->options.cardtype == -1) {
+ retval = -ENODEV;
+ goto err;
+ }
+ if (cx18_init_struct1(cx)) {
+ retval = -ENOMEM;
+ goto err;
+ }
+
+ CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
+
+ /* PCI Device Setup */
+ retval = cx18_setup_pci(cx, dev, pci_id);
+ if (retval != 0) {
+ if (retval == -EIO)
+ goto free_workqueue;
+ else if (retval == -ENXIO)
+ goto free_mem;
+ }
+ /* save cx in the pci struct for later use */
+ pci_set_drvdata(dev, cx);
+
+ /* map io memory */
+ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+ cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+ cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
+ CX18_MEM_SIZE);
+ if (!cx->enc_mem) {
+ CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
+ CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ retval = -ENOMEM;
+ goto free_mem;
+ }
+ cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
+ devtype = read_reg(0xC72028);
+ switch (devtype & 0xff000000) {
+ case 0xff000000:
+ CX18_INFO("cx23418 revision %08x (A)\n", devtype);
+ break;
+ case 0x01000000:
+ CX18_INFO("cx23418 revision %08x (B)\n", devtype);
+ break;
+ default:
+ CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
+ break;
+ }
+
+ cx18_init_power(cx, 1);
+ cx18_init_memory(cx);
+
+ cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET);
+ cx18_init_scb(cx);
+
+ cx18_gpio_init(cx);
+
+ /* active i2c */
+ CX18_DEBUG_INFO("activating i2c...\n");
+ if (init_cx18_i2c(cx)) {
+ CX18_ERR("Could not initialize i2c\n");
+ goto free_map;
+ }
+
+ CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
+
+ if (cx->card->hw_all & CX18_HW_TVEEPROM) {
+ /* Based on the model number the cardtype may be changed.
+ The PCI IDs are not always reliable. */
+ cx18_process_eeprom(cx);
+ }
+ if (cx->card->comment)
+ CX18_INFO("%s", cx->card->comment);
+ if (cx->card->v4l2_capabilities == 0) {
+ retval = -ENODEV;
+ goto free_i2c;
+ }
+ cx18_init_memory(cx);
+
+ /* Register IRQ */
+ retval = request_irq(cx->dev->irq, cx18_irq_handler,
+ IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
+ if (retval) {
+ CX18_ERR("Failed to register irq %d\n", retval);
+ goto free_i2c;
+ }
+
+ if (cx->std == 0)
+ cx->std = V4L2_STD_NTSC_M;
+
+ if (cx->options.tuner == -1) {
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
+ if ((cx->std & cx->card->tuners[i].std) == 0)
+ continue;
+ cx->options.tuner = cx->card->tuners[i].tuner;
+ break;
+ }
+ }
+ /* if no tuner was found, then pick the first tuner in the card list */
+ if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
+ cx->std = cx->card->tuners[0].std;
+ cx->options.tuner = cx->card->tuners[0].tuner;
+ }
+ if (cx->options.radio == -1)
+ cx->options.radio = (cx->card->radio_input.audio_type != 0);
+
+ /* The card is now fully identified, continue with card-specific
+ initialization. */
+ cx18_init_struct2(cx);
+
+ cx18_load_and_init_modules(cx);
+
+ if (cx->std & V4L2_STD_525_60) {
+ cx->is_60hz = 1;
+ cx->is_out_60hz = 1;
+ } else {
+ cx->is_50hz = 1;
+ cx->is_out_50hz = 1;
+ }
+ cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
+ vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+
+ if (cx->options.radio > 0)
+ cx->v4l2_cap |= V4L2_CAP_RADIO;
+
+ retval = cx18_streams_setup(cx);
+ if (retval) {
+ CX18_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
+ }
+ retval = cx18_streams_register(cx);
+ if (retval) {
+ CX18_ERR("Error %d registering devices\n", retval);
+ goto free_streams;
+ }
+
+ if (cx->options.tuner > -1) {
+ struct tuner_setup setup;
+
+ setup.addr = ADDR_UNSET;
+ setup.type = cx->options.tuner;
+ setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
+ setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+ cx18_reset_tuner_gpio : NULL;
+ cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup);
+ if (setup.type == TUNER_XC2028) {
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = cx->options.tuner,
+ .priv = &ctrl,
+ };
+ cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg);
+ }
+ }
+
+ /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+ are not. */
+ cx->tuner_std = cx->std;
+
+ cx18_init_on_first_open(cx);
+
+ CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
+
+ return 0;
+
+free_streams:
+ cx18_streams_cleanup(cx, 1);
+free_irq:
+ free_irq(cx->dev->irq, (void *)cx);
+free_i2c:
+ exit_cx18_i2c(cx);
+free_map:
+ cx18_iounmap(cx);
+free_mem:
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+free_workqueue:
+err:
+ if (retval == 0)
+ retval = -ENODEV;
+ CX18_ERR("Error %d on initialization\n", retval);
+
+ kfree(cx18_cards[cx18_cards_active]);
+ cx18_cards[cx18_cards_active] = NULL;
+ return retval;
+}
+
+int cx18_init_on_first_open(struct cx18 *cx)
+{
+ int video_input;
+ int fw_retry_count = 3;
+ struct v4l2_frequency vf;
+
+ if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
+ return -ENXIO;
+
+ if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
+ return 0;
+
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+ set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
+
+ /* Init the firmware twice to work around a silicon bug
+ * transport related. */
+
+ fw_retry_count = 3;
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+
+ vf.tuner = 0;
+ vf.type = V4L2_TUNER_ANALOG_TV;
+ vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+ /* Set initial frequency. For PAL/SECAM broadcasts no
+ 'default' channel exists AFAIK. */
+ if (cx->std == V4L2_STD_NTSC_M_JP)
+ vf.frequency = 1460; /* ch. 1 91250*16/1000 */
+ else if (cx->std & V4L2_STD_NTSC_M)
+ vf.frequency = 1076; /* ch. 4 67250*16/1000 */
+
+ video_input = cx->active_input;
+ cx->active_input++; /* Force update of input */
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+
+ /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+ in one place. */
+ cx->std++; /* Force full standard initialization */
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+ return 0;
+}
+
+static void cx18_remove(struct pci_dev *pci_dev)
+{
+ struct cx18 *cx = pci_get_drvdata(pci_dev);
+
+ CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
+
+ /* Stop all captures */
+ CX18_DEBUG_INFO("Stopping all streams\n");
+ if (atomic_read(&cx->capturing) > 0)
+ cx18_stop_all_captures(cx);
+
+ /* Interrupts */
+ sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ cx18_halt_firmware(cx);
+
+ cx18_streams_cleanup(cx, 1);
+
+ exit_cx18_i2c(cx);
+
+ free_irq(cx->dev->irq, (void *)cx);
+
+ cx18_iounmap(cx);
+
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+
+ pci_disable_device(cx->dev);
+
+ CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
+}
+
+/* define a pci_driver for card detection */
+static struct pci_driver cx18_pci_driver = {
+ .name = "cx18",
+ .id_table = cx18_pci_tbl,
+ .probe = cx18_probe,
+ .remove = cx18_remove,
+};
+
+static int module_start(void)
+{
+ printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
+
+ memset(cx18_cards, 0, sizeof(cx18_cards));
+
+ /* Validate parameters */
+ if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n",
+ CX18_MAX_CARDS - 1);
+ return -1;
+ }
+
+ if (cx18_debug < 0 || cx18_debug > 511) {
+ cx18_debug = 0;
+ printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
+ }
+
+ if (pci_register_driver(&cx18_pci_driver)) {
+ printk(KERN_ERR "cx18: Error detecting PCI card\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "cx18: End initialization\n");
+ return 0;
+}
+
+static void module_cleanup(void)
+{
+ int i;
+
+ pci_unregister_driver(&cx18_pci_driver);
+
+ for (i = 0; i < cx18_cards_active; i++) {
+ if (cx18_cards[i] == NULL)
+ continue;
+ kfree(cx18_cards[i]);
+ }
+}
+
+module_init(module_start);
+module_exit(module_cleanup);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
new file mode 100644
index 000000000000..a2a6c58d12fe
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -0,0 +1,497 @@
+/*
+ * cx18 driver internal defines and structures
+ *
+ * Derived from ivtv-driver.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 CX18_DRIVER_H
+#define CX18_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/byteorder/swab.h>
+#include <linux/pagemap.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "cx18-mailbox.h"
+#include "cx18-av-core.h"
+#include "cx23418.h"
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#ifndef CONFIG_PCI
+# error "This driver requires kernel PCI support."
+#endif
+
+#define CX18_MEM_OFFSET 0x00000000
+#define CX18_MEM_SIZE 0x04000000
+#define CX18_REG_OFFSET 0x02000000
+
+/* Maximum cx18 driver instances. */
+#define CX18_MAX_CARDS 32
+
+/* Supported cards */
+#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */
+#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
+#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
+#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
+#define CX18_CARD_LAST 3
+
+#define CX18_ENC_STREAM_TYPE_MPG 0
+#define CX18_ENC_STREAM_TYPE_TS 1
+#define CX18_ENC_STREAM_TYPE_YUV 2
+#define CX18_ENC_STREAM_TYPE_VBI 3
+#define CX18_ENC_STREAM_TYPE_PCM 4
+#define CX18_ENC_STREAM_TYPE_IDX 5
+#define CX18_ENC_STREAM_TYPE_RAD 6
+#define CX18_MAX_STREAMS 7
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_CX 0x14f1
+#define PCI_DEVICE_ID_CX23418 0x5b7a
+
+/* subsystem vendor ID */
+#define CX18_PCI_ID_HAUPPAUGE 0x0070
+#define CX18_PCI_ID_COMPRO 0x185b
+#define CX18_PCI_ID_YUAN 0x12ab
+
+/* ======================================================================== */
+/* ========================== START USER SETTABLE DMA VARIABLES =========== */
+/* ======================================================================== */
+
+/* DMA Buffers, Default size in MB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFFERS 1
+#define CX18_DEFAULT_ENC_MPG_BUFFERS 2
+#define CX18_DEFAULT_ENC_IDX_BUFFERS 1
+#define CX18_DEFAULT_ENC_YUV_BUFFERS 2
+#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
+#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
+
+/* i2c stuff */
+#define I2C_CLIENTS_MAX 16
+
+/* debugging */
+
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_WARN (1 << 0)
+#define CX18_DBGFLG_INFO (1 << 1)
+#define CX18_DBGFLG_API (1 << 2)
+#define CX18_DBGFLG_DMA (1 << 3)
+#define CX18_DBGFLG_IOCTL (1 << 4)
+#define CX18_DBGFLG_FILE (1 << 5)
+#define CX18_DBGFLG_I2C (1 << 6)
+#define CX18_DBGFLG_IRQ (1 << 7)
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_HIGHVOL (1 << 8)
+
+/* NOTE: extra space before comma in 'cx->num , ## args' is required for
+ gcc-2.95, otherwise it won't compile. */
+#define CX18_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & cx18_debug) \
+ printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
+ } while (0)
+#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+ printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
+ } while (0)
+#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+/* Standard kernel messages */
+#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
+
+/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
+#define MPEG_FRAME_TYPE_IFRAME 1
+#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
+#define MPEG_FRAME_TYPE_ALL 7
+
+#define CX18_MAX_PGM_INDEX (400)
+
+extern int cx18_debug;
+
+
+struct cx18_options {
+ int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */
+ int cardtype; /* force card type on load */
+ int tuner; /* set tuner on load */
+ int radio; /* enable/disable radio */
+};
+
+/* per-buffer bit flags */
+#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */
+
+/* per-stream, s_flags */
+#define CX18_F_S_CLAIMED 3 /* this stream is claimed */
+#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */
+#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */
+#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */
+#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
+
+/* per-cx18, i_flags */
+#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */
+#define CX18_F_I_EOS 4 /* End of encoder stream reached */
+#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */
+#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
+#define CX18_F_I_INITED 21 /* set after first open */
+#define CX18_F_I_FAILED 22 /* set if first open failed */
+
+/* These are the VBI types as they appear in the embedded VBI private packets. */
+#define CX18_SLICED_TYPE_TELETEXT_B (1)
+#define CX18_SLICED_TYPE_CAPTION_525 (4)
+#define CX18_SLICED_TYPE_WSS_625 (5)
+#define CX18_SLICED_TYPE_VPS (7)
+
+struct cx18_buffer {
+ struct list_head list;
+ dma_addr_t dma_handle;
+ u32 id;
+ unsigned long b_flags;
+ char *buf;
+
+ u32 bytesused;
+ u32 readpos;
+};
+
+struct cx18_queue {
+ struct list_head list;
+ u32 buffers;
+ u32 length;
+ u32 bytesused;
+};
+
+struct cx18_dvb {
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dmxdev dmxdev;
+ struct dvb_adapter dvb_adapter;
+ struct dvb_demux demux;
+ struct dvb_frontend *fe;
+ struct dvb_net dvbnet;
+ int enabled;
+ int feeding;
+
+ struct mutex feedlock;
+
+};
+
+struct cx18; /* forward reference */
+struct cx18_scb; /* forward reference */
+
+struct cx18_stream {
+ /* These first four fields are always set, even if the stream
+ is not actually created. */
+ struct video_device *v4l2dev; /* NULL when stream not created */
+ struct cx18 *cx; /* for ease of use */
+ const char *name; /* name of the stream */
+ int type; /* stream type */
+ u32 handle; /* task handle */
+ unsigned mdl_offset;
+
+ u32 id;
+ spinlock_t qlock; /* locks access to the queues */
+ unsigned long s_flags; /* status flags, see above */
+ int dma; /* can be PCI_DMA_TODEVICE,
+ PCI_DMA_FROMDEVICE or
+ PCI_DMA_NONE */
+ u64 dma_pts;
+ wait_queue_head_t waitq;
+
+ /* Buffer Stats */
+ u32 buffers;
+ u32 buf_size;
+ u32 buffers_stolen;
+
+ /* Buffer Queues */
+ struct cx18_queue q_free; /* free buffers */
+ struct cx18_queue q_full; /* full buffers */
+ struct cx18_queue q_io; /* waiting for I/O */
+
+ /* DVB / Digital Transport */
+ struct cx18_dvb dvb;
+};
+
+struct cx18_open_id {
+ u32 open_id;
+ int type;
+ enum v4l2_priority prio;
+ struct cx18 *cx;
+};
+
+/* forward declaration of struct defined in cx18-cards.h */
+struct cx18_card;
+
+
+#define CX18_VBI_FRAMES 32
+
+/* VBI data */
+struct vbi_info {
+ u32 enc_size;
+ u32 frame;
+ u8 cc_data_odd[256];
+ u8 cc_data_even[256];
+ int cc_pos;
+ u8 cc_no_update;
+ u8 vps[5];
+ u8 vps_found;
+ int wss;
+ u8 wss_found;
+ u8 wss_no_update;
+ u32 raw_decoder_line_size;
+ u8 raw_decoder_sav_odd_field;
+ u8 raw_decoder_sav_even_field;
+ u32 sliced_decoder_line_size;
+ u8 sliced_decoder_sav_odd_field;
+ u8 sliced_decoder_sav_even_field;
+ struct v4l2_format in;
+ /* convenience pointer to sliced struct in vbi_in union */
+ struct v4l2_sliced_vbi_format *sliced_in;
+ u32 service_set_in;
+ int insert_mpeg;
+
+ /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+ One for /dev/vbi0 and one for /dev/vbi8 */
+ struct v4l2_sliced_vbi_data sliced_data[36];
+
+ /* Buffer for VBI data inserted into MPEG stream.
+ The first byte is a dummy byte that's never used.
+ The next 16 bytes contain the MPEG header for the VBI data,
+ the remainder is the actual VBI data.
+ The max size accepted by the MPEG VBI reinsertion turns out
+ to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
+ where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
+ a single line header byte and 2 * 18 is the number of VBI lines per frame.
+
+ However, it seems that the data must be 1K aligned, so we have to
+ pad the data until the 1 or 2 K boundary.
+
+ This pointer array will allocate 2049 bytes to store each VBI frame. */
+ u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
+ u32 sliced_mpeg_size[CX18_VBI_FRAMES];
+ struct cx18_buffer sliced_mpeg_buf;
+ u32 inserted_frame;
+
+ u32 start[2], count;
+ u32 raw_size;
+ u32 sliced_size;
+};
+
+/* Per cx23418, per I2C bus private algo callback data */
+struct cx18_i2c_algo_callback_data {
+ struct cx18 *cx;
+ int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
+};
+
+/* Struct to hold info about cx18 cards */
+struct cx18 {
+ int num; /* board number, -1 during init! */
+ char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */
+ struct pci_dev *dev; /* PCI device */
+ const struct cx18_card *card; /* card information */
+ const char *card_name; /* full name of the card */
+ const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+ u8 is_50hz;
+ u8 is_60hz;
+ u8 is_out_50hz;
+ u8 is_out_60hz;
+ u8 nof_inputs; /* number of video inputs */
+ u8 nof_audio_inputs; /* number of audio inputs */
+ u16 buffer_id; /* buffer ID counter */
+ u32 v4l2_cap; /* V4L2 capabilities of card */
+ u32 hw_flags; /* Hardware description of the board */
+ unsigned mdl_offset;
+ struct cx18_scb *scb; /* pointer to SCB */
+
+ struct cx18_av_state av_state;
+
+ /* codec settings */
+ struct cx2341x_mpeg_params params;
+ u32 filter_mode;
+ u32 temporal_strength;
+ u32 spatial_strength;
+
+ /* dualwatch */
+ unsigned long dualwatch_jiffies;
+ u16 dualwatch_stereo_mode;
+
+ /* Digitizer type */
+ int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
+
+ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
+ struct cx18_options options; /* User options */
+ int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
+ struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
+ unsigned long i_flags; /* global cx18 flags */
+ atomic_t capturing; /* count number of active capture streams */
+ spinlock_t lock; /* lock access to this struct */
+ int search_pack_header;
+
+ spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+
+ int open_id; /* incremented each time an open occurs, used as
+ unique ID. Starts at 1, so 0 can be used as
+ uninitialized value in the stream->id. */
+
+ u32 base_addr;
+ struct v4l2_prio_state prio;
+
+ u8 card_rev;
+ void __iomem *enc_mem, *reg_mem;
+
+ struct vbi_info vbi;
+
+ u32 pgm_info_offset;
+ u32 pgm_info_num;
+ u32 pgm_info_write_idx;
+ u32 pgm_info_read_idx;
+ struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX];
+
+ u64 mpg_data_received;
+ u64 vbi_data_inserted;
+
+ wait_queue_head_t mb_apu_waitq;
+ wait_queue_head_t mb_cpu_waitq;
+ wait_queue_head_t mb_epu_waitq;
+ wait_queue_head_t mb_hpu_waitq;
+ wait_queue_head_t cap_w;
+ /* when the current DMA is finished this queue is woken up */
+ wait_queue_head_t dma_waitq;
+
+ /* i2c */
+ struct i2c_adapter i2c_adap[2];
+ struct i2c_algo_bit_data i2c_algo[2];
+ struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
+ struct i2c_client i2c_client[2];
+ struct mutex i2c_bus_lock[2];
+ struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+
+ /* v4l2 and User settings */
+
+ /* codec settings */
+ u32 audio_input;
+ u32 active_input;
+ u32 active_output;
+ v4l2_std_id std;
+ v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
+};
+
+/* Globals */
+extern struct cx18 *cx18_cards[];
+extern int cx18_cards_active;
+extern int cx18_first_minor;
+extern spinlock_t cx18_cards_lock;
+
+/*==============Prototypes==================*/
+
+/* Return non-zero if a signal is pending */
+int cx18_msleep_timeout(unsigned int msecs, int intr);
+
+/* Read Hauppauge eeprom */
+struct tveeprom; /* forward reference */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
+
+/* First-open initialization: load firmware, etc. */
+int cx18_init_on_first_open(struct cx18 *cx);
+
+/* This is a PCI post thing, where if the pci register is not read, then
+ the write doesn't always take effect right away. By reading back the
+ register any pending PCI writes will be performed (in order), and so
+ you can be sure that the writes are guaranteed to be done.
+
+ Rarely needed, only in some timing sensitive cases.
+ Apparently if this is not done some motherboards seem
+ to kill the firmware and get into the broken state until computer is
+ rebooted. */
+#define write_sync(val, reg) \
+ do { writel(val, reg); readl(reg); } while (0)
+
+#define read_reg(reg) readl(cx->reg_mem + (reg))
+#define write_reg(val, reg) writel(val, cx->reg_mem + (reg))
+#define write_reg_sync(val, reg) \
+ do { write_reg(val, reg); read_reg(reg); } while (0)
+
+#define read_enc(addr) readl(cx->enc_mem + (u32)(addr))
+#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr))
+#define write_enc_sync(val, addr) \
+ do { write_enc(val, addr); read_enc(addr); } while (0)
+
+#define sw1_irq_enable(val) do { \
+ write_reg(val, SW1_INT_STATUS); \
+ write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \
+} while (0)
+
+#define sw1_irq_disable(val) \
+ write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI);
+
+#define sw2_irq_enable(val) do { \
+ write_reg(val, SW2_INT_STATUS); \
+ write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \
+} while (0)
+
+#define sw2_irq_disable(val) \
+ write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI);
+
+#define setup_page(addr) do { \
+ u32 val = read_reg(0xD000F8) & ~0x1f00; \
+ write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \
+} while (0)
+
+#endif /* CX18_DRIVER_H */
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
new file mode 100644
index 000000000000..c9744173f969
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -0,0 +1,286 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx18-version.h"
+#include "cx18-dvb.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "s5h1409.h"
+#include "mxl5005s.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+
+static struct mxl5005s_config hauppauge_hvr1600_tuner = {
+ .i2c_address = 0xC6 >> 1,
+ .if_freq = IF_FREQ_5380000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_C_H,
+ .rssi_enable = MXL_RSSI_ENABLE,
+ .cap_select = MXL_CAP_SEL_ENABLE,
+ .div_out = MXL_DIV_OUT_4,
+ .clock_out = MXL_CLOCK_OUT_DISABLE,
+ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+ .top = MXL5005S_TOP_25P2,
+ .mod_mode = MXL_DIGITAL_MODE,
+ .if_mode = MXL_ZERO_IF,
+ .AgcMasterByte = 0x00,
+};
+
+static struct s5h1409_config hauppauge_hvr1600_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+
+};
+
+static int dvb_register(struct cx18_stream *stream);
+
+/* Kernel DVB framework calls this when the feed needs to start.
+ * The CX18 framework should enable the transport DMA handling
+ * and queue processing.
+ */
+static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
+ struct cx18 *cx = stream->cx;
+ int ret = -EINVAL;
+ u32 v;
+
+ CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ v |= 0x00400000; /* Serial Mode */
+ v |= 0x00002000; /* Data Length - Byte */
+ v |= 0x00010000; /* Error - Polarity */
+ v |= 0x00020000; /* Error - Passthru */
+ v |= 0x000c0000; /* Error - Ignore */
+ write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ break;
+
+ default:
+ /* Assumption - Parallel transport - Signalling
+ * undefined or default.
+ */
+ break;
+ }
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ if (stream) {
+ mutex_lock(&stream->dvb.feedlock);
+ if (stream->dvb.feeding++ == 0) {
+ CX18_DEBUG_INFO("Starting Transport DMA\n");
+ ret = cx18_start_v4l2_encode_stream(stream);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb.feedlock);
+ }
+
+ return ret;
+}
+
+/* Kernel DVB framework calls this when the feed needs to stop. */
+static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
+ struct cx18 *cx = stream->cx;
+ int ret = -EINVAL;
+
+ CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+
+ if (stream) {
+ mutex_lock(&stream->dvb.feedlock);
+ if (--stream->dvb.feeding == 0) {
+ CX18_DEBUG_INFO("Stopping Transport DMA\n");
+ ret = cx18_stop_v4l2_encode_stream(stream, 0);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb.feedlock);
+ }
+
+ return ret;
+}
+
+int cx18_dvb_register(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+ int ret;
+
+ if (!dvb)
+ return -EINVAL;
+
+ ret = dvb_register_adapter(&dvb->dvb_adapter,
+ CX18_DRIVER_NAME,
+ THIS_MODULE, &cx->dev->dev, adapter_nr);
+ if (ret < 0)
+ goto err_out;
+
+ dvb_adapter = &dvb->dvb_adapter;
+
+ dvbdemux = &dvb->demux;
+
+ dvbdemux->priv = (void *)stream;
+
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = cx18_dvb_start_feed;
+ dvbdemux->stop_feed = cx18_dvb_stop_feed;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter;
+
+ dmx = &dvbdemux->dmx;
+
+ dvb->hw_frontend.source = DMX_FRONTEND_0;
+ dvb->mem_frontend.source = DMX_MEMORY_FE;
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = dmx;
+
+ ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
+ if (ret < 0)
+ goto err_dvb_dmx_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_dvb_dmxdev_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
+ if (ret < 0)
+ goto err_remove_hw_frontend;
+
+ ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_remove_mem_frontend;
+
+ ret = dvb_register(stream);
+ if (ret < 0)
+ goto err_disconnect_frontend;
+
+ dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
+
+ CX18_INFO("DVB Frontend registered\n");
+ mutex_init(&dvb->feedlock);
+ dvb->enabled = 1;
+ return ret;
+
+err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+err_remove_hw_frontend:
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+err_dvb_dmxdev_release:
+ dvb_dmxdev_release(&dvb->dmxdev);
+err_dvb_dmx_release:
+ dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+ dvb_unregister_adapter(dvb_adapter);
+err_out:
+ return ret;
+}
+
+void cx18_dvb_unregister(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+
+ CX18_INFO("unregister DVB\n");
+
+ dvb_adapter = &dvb->dvb_adapter;
+ dvbdemux = &dvb->demux;
+ dmx = &dvbdemux->dmx;
+
+ dmx->close(dmx);
+ dvb_net_release(&dvb->dvbnet);
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(dvbdemux);
+ dvb_unregister_frontend(dvb->fe);
+ dvb_frontend_detach(dvb->fe);
+ dvb_unregister_adapter(dvb_adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+static int dvb_register(struct cx18_stream *stream)
+{
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18 *cx = stream->cx;
+ int ret = 0;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ dvb->fe = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1600_config,
+ &cx->i2c_adap[0]);
+ if (dvb->fe != NULL) {
+ dvb_attach(mxl5005s_attach, dvb->fe,
+ &cx->i2c_adap[0],
+ &hauppauge_hvr1600_tuner);
+ ret = 0;
+ }
+ break;
+ default:
+ /* No Digital Tv Support */
+ break;
+ }
+
+ if (dvb->fe == NULL) {
+ CX18_ERR("frontend initialization failed\n");
+ return -1;
+ }
+
+ ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
+ if (ret < 0) {
+ if (dvb->fe->ops.release)
+ dvb->fe->ops.release(dvb->fe);
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h
new file mode 100644
index 000000000000..d6a6ccda79a9
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-dvb.h
@@ -0,0 +1,25 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx18-driver.h"
+
+int cx18_dvb_register(struct cx18_stream *stream);
+void cx18_dvb_unregister(struct cx18_stream *stream);
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
new file mode 100644
index 000000000000..0b3141db174b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -0,0 +1,713 @@
+/*
+ * cx18 file operation functions
+ *
+ * Derived from ivtv-fileops.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-mailbox.h"
+#include "cx18-scb.h"
+#include "cx18-streams.h"
+#include "cx18-controls.h"
+#include "cx18-ioctl.h"
+#include "cx18-cards.h"
+
+/* This function tries to claim the stream for a specific file descriptor.
+ If no one else is using this stream then the stream is claimed and
+ associated VBI streams are also automatically claimed.
+ Possible error returns: -EBUSY if someone else has claimed
+ the stream or 0 on success. */
+static int cx18_claim_stream(struct cx18_open_id *id, int type)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[type];
+ struct cx18_stream *s_vbi;
+ int vbi_type;
+
+ if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+ /* someone already claimed this stream */
+ if (s->id == id->open_id) {
+ /* yes, this file descriptor did. So that's OK. */
+ return 0;
+ }
+ if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
+ /* VBI is handled already internally, now also assign
+ the file descriptor to this stream for external
+ reading of the stream. */
+ s->id = id->open_id;
+ CX18_DEBUG_INFO("Start Read VBI\n");
+ return 0;
+ }
+ /* someone else is using this stream already */
+ CX18_DEBUG_INFO("Stream %d is busy\n", type);
+ return -EBUSY;
+ }
+ s->id = id->open_id;
+
+ /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
+ CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+ (provided VBI insertion is on and sliced VBI is selected), for all
+ other streams we're done */
+ if (type == CX18_ENC_STREAM_TYPE_MPG &&
+ cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+ vbi_type = CX18_ENC_STREAM_TYPE_VBI;
+ } else {
+ return 0;
+ }
+ s_vbi = &cx->streams[vbi_type];
+
+ set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+
+ /* mark that it is used internally */
+ set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags);
+ return 0;
+}
+
+/* This function releases a previously claimed stream. It will take into
+ account associated VBI streams. */
+static void cx18_release_stream(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_stream *s_vbi;
+
+ s->id = -1;
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
+ /* this stream is still in use internally */
+ return;
+ }
+ if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+ CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+ return;
+ }
+
+ cx18_flush_queues(s);
+
+ /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI,
+ for all other streams we're done */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ else
+ return;
+
+ /* clear internal use flag */
+ if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
+ /* was already cleared */
+ return;
+ }
+ if (s_vbi->id != -1) {
+ /* VBI stream still claimed by a file descriptor */
+ return;
+ }
+ clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+ cx18_flush_queues(s_vbi);
+}
+
+static void cx18_dualwatch(struct cx18 *cx)
+{
+ struct v4l2_tuner vt;
+ u16 new_bitmap;
+ u16 new_stereo_mode;
+ const u16 stereo_mask = 0x0300;
+ const u16 dual = 0x0200;
+
+ new_stereo_mode = cx->params.audio_properties & stereo_mask;
+ memset(&vt, 0, sizeof(vt));
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
+ if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
+ (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+ new_stereo_mode = dual;
+
+ if (new_stereo_mode == cx->dualwatch_stereo_mode)
+ return;
+
+ new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
+
+ CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
+ cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+
+ if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+ cx18_find_handle(cx), new_bitmap) == 0) {
+ cx->dualwatch_stereo_mode = new_stereo_mode;
+ return;
+ }
+ CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+
+static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ struct cx18_buffer *buf;
+ DEFINE_WAIT(wait);
+
+ *err = 0;
+ while (1) {
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+
+ if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
+ cx->dualwatch_jiffies = jiffies;
+ cx18_dualwatch(cx);
+ }
+ if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
+ /* byteswap and process VBI data */
+/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
+ cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
+ }
+ }
+ buf = &cx->vbi.sliced_mpeg_buf;
+ if (buf->readpos != buf->bytesused)
+ return buf;
+ }
+
+ /* do we have leftover data? */
+ buf = cx18_dequeue(s, &s->q_io);
+ if (buf)
+ return buf;
+
+ /* do we have new data? */
+ buf = cx18_dequeue(s, &s->q_full);
+ if (buf) {
+ if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP,
+ &buf->b_flags))
+ return buf;
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ /* byteswap MPG data */
+ cx18_buf_swap(buf);
+ else {
+ /* byteswap and process VBI data */
+ cx18_process_vbi_data(cx, buf,
+ s->dma_pts, s->type);
+ }
+ return buf;
+ }
+
+ /* return if end of stream */
+ if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ CX18_DEBUG_INFO("EOS %s\n", s->name);
+ return NULL;
+ }
+
+ /* return if file was opened with O_NONBLOCK */
+ if (non_block) {
+ *err = -EAGAIN;
+ return NULL;
+ }
+
+ /* wait for more data to arrive */
+ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+ /* New buffers might have become available before we were added
+ to the waitqueue */
+ if (!s->q_full.buffers)
+ schedule();
+ finish_wait(&s->waitq, &wait);
+ if (signal_pending(current)) {
+ /* return if a signal was received */
+ CX18_DEBUG_INFO("User stopped %s\n", s->name);
+ *err = -EINTR;
+ return NULL;
+ }
+ }
+}
+
+static void cx18_setup_sliced_vbi_buf(struct cx18 *cx)
+{
+ int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+ cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx];
+ cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx];
+ cx->vbi.sliced_mpeg_buf.readpos = 0;
+}
+
+static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
+ struct cx18_buffer *buf, char __user *ubuf, size_t ucount)
+{
+ struct cx18 *cx = s->cx;
+ size_t len = buf->bytesused - buf->readpos;
+
+ if (len > ucount)
+ len = ucount;
+ if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+ const char *start = buf->buf + buf->readpos;
+ const char *p = start + 1;
+ const u8 *q;
+ u8 ch = cx->search_pack_header ? 0xba : 0xe0;
+ int stuffing, i;
+
+ while (start + len > p) {
+ q = memchr(p, 0, start + len - p);
+ if (q == NULL)
+ break;
+ p = q + 1;
+ if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+ q[1] != 0 || q[2] != 1 || q[3] != ch)
+ continue;
+ if (!cx->search_pack_header) {
+ if ((q[6] & 0xc0) != 0x80)
+ continue;
+ if (((q[7] & 0xc0) == 0x80 &&
+ (q[9] & 0xf0) == 0x20) ||
+ ((q[7] & 0xc0) == 0xc0 &&
+ (q[9] & 0xf0) == 0x30)) {
+ ch = 0xba;
+ cx->search_pack_header = 1;
+ p = q + 9;
+ }
+ continue;
+ }
+ stuffing = q[13] & 7;
+ /* all stuffing bytes must be 0xff */
+ for (i = 0; i < stuffing; i++)
+ if (q[14 + i] != 0xff)
+ break;
+ if (i == stuffing &&
+ (q[4] & 0xc4) == 0x44 &&
+ (q[12] & 3) == 3 &&
+ q[14 + stuffing] == 0 &&
+ q[15 + stuffing] == 0 &&
+ q[16 + stuffing] == 1) {
+ cx->search_pack_header = 0;
+ len = (char *)q - start;
+ cx18_setup_sliced_vbi_buf(cx);
+ break;
+ }
+ }
+ }
+ if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+ CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n",
+ len, s->name);
+ return -EFAULT;
+ }
+ buf->readpos += len;
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ buf != &cx->vbi.sliced_mpeg_buf)
+ cx->mpg_data_received += len;
+ return len;
+}
+
+static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
+ size_t tot_count, int non_block)
+{
+ struct cx18 *cx = s->cx;
+ size_t tot_written = 0;
+ int single_frame = 0;
+
+ if (atomic_read(&cx->capturing) == 0 && s->id == -1) {
+ /* shouldn't happen */
+ CX18_DEBUG_WARN("Stream %s not initialized before read\n",
+ s->name);
+ return -EIO;
+ }
+
+ /* Each VBI buffer is one frame, the v4l2 API says that for VBI the
+ frames should arrive one-by-one, so make sure we never output more
+ than one VBI frame at a time */
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set)
+ single_frame = 1;
+
+ for (;;) {
+ struct cx18_buffer *buf;
+ int rc;
+
+ buf = cx18_get_buffer(s, non_block, &rc);
+ /* if there is no data available... */
+ if (buf == NULL) {
+ /* if we got data, then return that regardless */
+ if (tot_written)
+ break;
+ /* EOS condition */
+ if (rc == 0) {
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ cx18_release_stream(s);
+ }
+ /* set errno */
+ return rc;
+ }
+
+ rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written,
+ tot_count - tot_written);
+
+ if (buf != &cx->vbi.sliced_mpeg_buf) {
+ if (buf->readpos == buf->bytesused) {
+ cx18_buf_sync_for_device(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
+ s->handle,
+ (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ } else
+ cx18_enqueue(s, buf, &s->q_io);
+ } else if (buf->readpos == buf->bytesused) {
+ int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+ cx->vbi.sliced_mpeg_size[idx] = 0;
+ cx->vbi.inserted_frame++;
+ cx->vbi_data_inserted += buf->bytesused;
+ }
+ if (rc < 0)
+ return rc;
+ tot_written += rc;
+
+ if (tot_written == tot_count || single_frame)
+ break;
+ }
+ return tot_written;
+}
+
+static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf,
+ size_t count, loff_t *pos, int non_block)
+{
+ ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0;
+ struct cx18 *cx = s->cx;
+
+ CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
+ if (rc > 0)
+ pos += rc;
+ return rc;
+}
+
+int cx18_start_capture(struct cx18_open_id *id)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ struct cx18_stream *s_vbi;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* you cannot read from these stream types. */
+ return -EPERM;
+ }
+
+ /* Try to claim this stream. */
+ if (cx18_claim_stream(id, s->type))
+ return -EBUSY;
+
+ /* If capture is already in progress, then we also have to
+ do nothing extra. */
+ if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
+ test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ return 0;
+ }
+
+ /* Start VBI capture if required */
+ s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed
+ automatically when the MPG stream is claimed.
+ We only need to start the VBI capturing. */
+ if (cx18_start_v4l2_encode_stream(s_vbi)) {
+ CX18_DEBUG_WARN("VBI capture start failed\n");
+
+ /* Failure, clean up and return an error */
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ /* also releases the associated VBI stream */
+ cx18_release_stream(s);
+ return -EIO;
+ }
+ CX18_DEBUG_INFO("VBI insertion started\n");
+ }
+
+ /* Tell the card to start capturing */
+ if (!cx18_start_v4l2_encode_stream(s)) {
+ /* We're done */
+ set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ /* Resume a possibly paused encoder */
+ if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);
+ return 0;
+ }
+
+ /* failure, clean up */
+ CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+ /* Note: the CX18_ENC_STREAM_TYPE_VBI is released
+ automatically when the MPG stream is released.
+ We only need to stop the VBI capturing. */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ }
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ cx18_release_stream(s);
+ return -EIO;
+}
+
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int rc;
+
+ CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc)
+ return rc;
+ return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+}
+
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ /* Start a capture if there is none */
+ if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ int rc;
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc) {
+ CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",
+ s->name, rc);
+ return POLLERR;
+ }
+ CX18_DEBUG_FILE("Encoder poll started capture\n");
+ }
+
+ /* add stream's waitq to the poll list */
+ CX18_DEBUG_HI_FILE("Encoder poll\n");
+ poll_wait(filp, &s->waitq, wait);
+
+ if (s->q_full.length || s->q_io.length)
+ return POLLIN | POLLRDNORM;
+ if (eof)
+ return POLLHUP;
+ return 0;
+}
+
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+ /* 'Unclaim' this stream */
+
+ /* Stop capturing */
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ struct cx18_stream *s_vbi =
+ &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+
+ CX18_DEBUG_INFO("close stopping capture\n");
+ /* Special case: a running VBI capture for VBI insertion
+ in the mpeg stream. Need to stop that too. */
+ if (id->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ CX18_DEBUG_INFO("close stopping embedded VBI capture\n");
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ }
+ if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
+ /* Also used internally, don't stop capturing */
+ s->id = -1;
+ else
+ cx18_stop_v4l2_encode_stream(s, gop_end);
+ }
+ if (!gop_end) {
+ clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ cx18_release_stream(s);
+ }
+}
+
+int cx18_v4l2_close(struct inode *inode, struct file *filp)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+ v4l2_prio_close(&cx->prio, &id->prio);
+
+ /* Easy case first: this stream was never claimed by us */
+ if (s->id != id->open_id) {
+ kfree(id);
+ return 0;
+ }
+
+ /* 'Unclaim' this stream */
+
+ /* Stop radio */
+ mutex_lock(&cx->serialize_lock);
+ if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Closing radio device, return to TV mode */
+ cx18_mute(cx);
+ /* Mark that the radio is no longer in use */
+ clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* Switch tuner to TV */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ /* Select correct audio input (i.e. TV tuner or Line in) */
+ cx18_audio_set_io(cx);
+ if (atomic_read(&cx->capturing) > 0) {
+ /* Undo video mute */
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+ cx->params.video_mute |
+ (cx->params.video_mute_yuv << 8));
+ }
+ /* Done! Unmute and continue. */
+ cx18_unmute(cx);
+ cx18_release_stream(s);
+ } else {
+ cx18_stop_capture(id, 0);
+ }
+ kfree(id);
+ mutex_unlock(&cx->serialize_lock);
+ return 0;
+}
+
+static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_open_id *item;
+
+ CX18_DEBUG_FILE("open %s\n", s->name);
+
+ /* Allocate memory */
+ item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
+ if (NULL == item) {
+ CX18_DEBUG_WARN("nomem on v4l2 open\n");
+ return -ENOMEM;
+ }
+ item->cx = cx;
+ item->type = s->type;
+ v4l2_prio_open(&cx->prio, &item->prio);
+
+ item->open_id = cx->open_id++;
+ filp->private_data = item;
+
+ if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Try to claim this stream */
+ if (cx18_claim_stream(item, item->type)) {
+ /* No, it's already in use */
+ kfree(item);
+ return -EBUSY;
+ }
+
+ if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ if (atomic_read(&cx->capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ cx18_release_stream(s);
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+
+ /* Mark that the radio is being used. */
+ set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* We have the radio */
+ cx18_mute(cx);
+ /* Switch tuner to radio */
+ cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
+ /* Select the correct audio input (i.e. radio tuner) */
+ cx18_audio_set_io(cx);
+ /* Done! Unmute and continue. */
+ cx18_unmute(cx);
+ }
+ return 0;
+}
+
+int cx18_v4l2_open(struct inode *inode, struct file *filp)
+{
+ int res, x, y = 0;
+ struct cx18 *cx = NULL;
+ struct cx18_stream *s = NULL;
+ int minor = iminor(inode);
+
+ /* Find which card this open was on */
+ spin_lock(&cx18_cards_lock);
+ for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
+ /* find out which stream this open was on */
+ for (y = 0; y < CX18_MAX_STREAMS; y++) {
+ if (cx18_cards[x] == NULL)
+ continue;
+ s = &cx18_cards[x]->streams[y];
+ if (s->v4l2dev && s->v4l2dev->minor == minor) {
+ cx = cx18_cards[x];
+ break;
+ }
+ }
+ }
+ spin_unlock(&cx18_cards_lock);
+
+ if (cx == NULL) {
+ /* Couldn't find a device registered
+ on that minor, shouldn't happen! */
+ printk(KERN_WARNING "No cx18 device found on minor %d\n",
+ minor);
+ return -ENXIO;
+ }
+
+ mutex_lock(&cx->serialize_lock);
+ if (cx18_init_on_first_open(cx)) {
+ CX18_ERR("Failed to initialize on minor %d\n", minor);
+ mutex_unlock(&cx->serialize_lock);
+ return -ENXIO;
+ }
+ res = cx18_serialized_open(s, filp);
+ mutex_unlock(&cx->serialize_lock);
+ return res;
+}
+
+void cx18_mute(struct cx18 *cx)
+{
+ if (atomic_read(&cx->capturing))
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ cx18_find_handle(cx), 1);
+ CX18_DEBUG_INFO("Mute\n");
+}
+
+void cx18_unmute(struct cx18 *cx)
+{
+ if (atomic_read(&cx->capturing)) {
+ cx18_msleep_timeout(100, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
+ cx18_find_handle(cx), 12);
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ cx18_find_handle(cx), 0);
+ }
+ CX18_DEBUG_INFO("Unmute\n");
+}
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
new file mode 100644
index 000000000000..46da0282fc7d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -0,0 +1,36 @@
+/*
+ * cx18 file operation functions
+ *
+ * Derived from ivtv-fileops.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+/* Testing/Debugging */
+int cx18_v4l2_open(struct inode *inode, struct file *filp);
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos);
+ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *pos);
+int cx18_v4l2_close(struct inode *inode, struct file *filp);
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
+int cx18_start_capture(struct cx18_open_id *id);
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
+void cx18_mute(struct cx18 *cx);
+void cx18_unmute(struct cx18 *cx);
+
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
new file mode 100644
index 000000000000..2694ce350631
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -0,0 +1,373 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-firmware.h"
+#include "cx18-cards.h"
+#include <linux/firmware.h>
+
+#define CX18_PROC_SOFT_RESET 0xc70010
+#define CX18_DDR_SOFT_RESET 0xc70014
+#define CX18_CLOCK_SELECT1 0xc71000
+#define CX18_CLOCK_SELECT2 0xc71004
+#define CX18_HALF_CLOCK_SELECT1 0xc71008
+#define CX18_HALF_CLOCK_SELECT2 0xc7100C
+#define CX18_CLOCK_POLARITY1 0xc71010
+#define CX18_CLOCK_POLARITY2 0xc71014
+#define CX18_ADD_DELAY_ENABLE1 0xc71018
+#define CX18_ADD_DELAY_ENABLE2 0xc7101C
+#define CX18_CLOCK_ENABLE1 0xc71020
+#define CX18_CLOCK_ENABLE2 0xc71024
+
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_FAST_CLOCK_PLL_INT 0xc78000
+#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
+#define CX18_FAST_CLOCK_PLL_POST 0xc78008
+#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
+#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
+
+#define CX18_SLOW_CLOCK_PLL_INT 0xc78014
+#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
+#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
+#define CX18_MPEG_CLOCK_PLL_INT 0xc78040
+#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
+#define CX18_MPEG_CLOCK_PLL_POST 0xc78048
+#define CX18_PLL_POWER_DOWN 0xc78088
+#define CX18_SW1_INT_STATUS 0xc73104
+#define CX18_SW1_INT_ENABLE_PCI 0xc7311C
+#define CX18_SW2_INT_SET 0xc73140
+#define CX18_SW2_INT_STATUS 0xc73144
+#define CX18_ADEC_CONTROL 0xc78120
+
+#define CX18_DDR_REQUEST_ENABLE 0xc80000
+#define CX18_DDR_CHIP_CONFIG 0xc80004
+#define CX18_DDR_REFRESH 0xc80008
+#define CX18_DDR_TIMING1 0xc8000C
+#define CX18_DDR_TIMING2 0xc80010
+#define CX18_DDR_POWER_REG 0xc8001C
+
+#define CX18_DDR_TUNE_LANE 0xc80048
+#define CX18_DDR_INITIAL_EMRS 0xc80054
+#define CX18_DDR_MB_PER_ROW_7 0xc8009C
+#define CX18_DDR_BASE_63_ADDR 0xc804FC
+
+#define CX18_WMB_CLIENT02 0xc90108
+#define CX18_WMB_CLIENT05 0xc90114
+#define CX18_WMB_CLIENT06 0xc90118
+#define CX18_WMB_CLIENT07 0xc9011C
+#define CX18_WMB_CLIENT08 0xc90120
+#define CX18_WMB_CLIENT09 0xc90124
+#define CX18_WMB_CLIENT10 0xc90128
+#define CX18_WMB_CLIENT11 0xc9012C
+#define CX18_WMB_CLIENT12 0xc90130
+#define CX18_WMB_CLIENT13 0xc90134
+#define CX18_WMB_CLIENT14 0xc90138
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+/* Encoder/decoder firmware sizes */
+#define CX18_FW_CPU_SIZE (174716)
+#define CX18_FW_APU_SIZE (141200)
+
+#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
+#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
+
+struct cx18_apu_rom_seghdr {
+ u32 sync1;
+ u32 sync2;
+ u32 addr;
+ u32 size;
+};
+
+static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+ int i, j;
+ u32 __iomem *dst = (u32 __iomem *)mem;
+ const u32 *src;
+
+retry:
+ if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
+ CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n",
+ fn, size);
+ CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with
+ udev <0.95) the wrong file was sometimes loaded. So we check
+ filesizes to see if at least the right-sized file was
+ loaded. If not, then we retry. */
+ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
+ fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ for (i = 0; i < fw->size; i += 4096) {
+ setup_page(i);
+ for (j = i; j < fw->size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(*src, dst);
+ if (__raw_readl(dst) != *src) {
+ CX18_ERR("Mismatch at offset %x\n", i);
+ release_firmware(fw);
+ return -EIO;
+ }
+ dst++;
+ src++;
+ }
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ release_firmware(fw);
+ return size;
+}
+
+static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+ int i, j;
+ const u32 *src;
+ struct cx18_apu_rom_seghdr seghdr;
+ const u8 *vers;
+ u32 offset = 0;
+ u32 apu_version = 0;
+ int sz;
+
+retry:
+ if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
+ CX18_ERR("unable to open firmware %s (must be %ld bytes)\n",
+ fn, size);
+ CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+ vers = fw->data + sizeof(seghdr);
+ sz = fw->size;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with
+ udev <0.95) the wrong file was sometimes loaded. So we check
+ filesizes to see if at least the right-sized file was
+ loaded. If not, then we retry. */
+ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
+ fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
+ while (offset + sizeof(seghdr) < size) {
+ /* TODO: byteswapping */
+ memcpy(&seghdr, src + offset / 4, sizeof(seghdr));
+ offset += sizeof(seghdr);
+ if (seghdr.sync1 != APU_ROM_SYNC1 ||
+ seghdr.sync2 != APU_ROM_SYNC2) {
+ offset += seghdr.size;
+ continue;
+ }
+ CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
+ seghdr.addr + seghdr.size - 1);
+ if (offset + seghdr.size > sz)
+ break;
+ for (i = 0; i < seghdr.size; i += 4096) {
+ setup_page(offset + i);
+ for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j);
+ if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) {
+ CX18_ERR("Mismatch at offset %x\n", offset + j);
+ release_firmware(fw);
+ return -EIO;
+ }
+ }
+ }
+ offset += seghdr.size;
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+ fn, apu_version, fw->size);
+ release_firmware(fw);
+ /* Clear bit0 for APU to start from 0 */
+ write_reg(read_reg(0xc72030) & ~1, 0xc72030);
+ return size;
+}
+
+void cx18_halt_firmware(struct cx18 *cx)
+{
+ CX18_DEBUG_INFO("Preparing for firmware halt.\n");
+ write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+ write_reg(0x00020002, CX18_ADEC_CONTROL);
+}
+
+void cx18_init_power(struct cx18 *cx, int lowpwr)
+{
+ /* power-down Spare and AOM PLLs */
+ /* power-up fast, slow and mpeg PLLs */
+ write_reg(0x00000008, CX18_PLL_POWER_DOWN);
+
+ /* ADEC out of sleep */
+ write_reg(0x00020000, CX18_ADEC_CONTROL);
+
+ /* The fast clock is at 200/245 MHz */
+ write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+ write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC);
+
+ write_reg(2, CX18_FAST_CLOCK_PLL_POST);
+ write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE);
+ write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+
+ /* set slow clock to 125/120 MHz */
+ write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
+ write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC);
+ write_reg(4, CX18_SLOW_CLOCK_PLL_POST);
+
+ /* mpeg clock pll 54MHz */
+ write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT);
+ write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+ write_reg(8, CX18_MPEG_CLOCK_PLL_POST);
+
+ /* Defaults */
+ /* APU = SC or SC/2 = 125/62.5 */
+ /* EPU = SC = 125 */
+ /* DDR = FC = 180 */
+ /* ENC = SC = 125 */
+ /* AI1 = SC = 125 */
+ /* VIM2 = disabled */
+ /* PCI = FC/2 = 90 */
+ /* AI2 = disabled */
+ /* DEMUX = disabled */
+ /* AO = SC/2 = 62.5 */
+ /* SER = 54MHz */
+ /* VFC = disabled */
+ /* USB = disabled */
+
+ write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1);
+ write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2);
+
+ write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
+ write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
+
+ write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1);
+ write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2);
+}
+
+void cx18_init_memory(struct cx18 *cx)
+{
+ cx18_msleep_timeout(10, 0);
+ write_reg(0x10000, CX18_DDR_SOFT_RESET);
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH);
+ write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1);
+ write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2);
+
+ cx18_msleep_timeout(10, 0);
+
+ /* Initialize DQS pad time */
+ write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+ write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(0x20000, CX18_DDR_SOFT_RESET);
+ cx18_msleep_timeout(10, 0);
+
+ /* use power-down mode when idle */
+ write_reg(0x00000010, CX18_DDR_POWER_REG);
+
+ write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN);
+
+ write_reg(0x48, CX18_DDR_MB_PER_ROW_7);
+ write_reg(0xE0000, CX18_DDR_BASE_63_ADDR);
+
+ write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */
+ write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */
+ write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
+ write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */
+ write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
+ write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */
+ write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */
+ write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */
+ write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */
+ write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */
+}
+
+int cx18_firmware_init(struct cx18 *cx)
+{
+ /* Allow chip to control CLKRUN */
+ write_reg(0x5, CX18_DSP0_INTERRUPT_MASK);
+
+ write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+
+ cx18_msleep_timeout(1, 0);
+
+ sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ /* Only if the processor is not running */
+ if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
+ int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
+ cx->enc_mem, cx, CX18_FW_APU_SIZE);
+
+ sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
+ cx->enc_mem, cx, CX18_FW_CPU_SIZE);
+
+ if (sz > 0) {
+ int retries = 0;
+
+ /* start the CPU */
+ write_reg(0x00080000, CX18_PROC_SOFT_RESET);
+ while (retries++ < 50) { /* Loop for max 500mS */
+ if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0)
+ break;
+ cx18_msleep_timeout(10, 0);
+ }
+ cx18_msleep_timeout(200, 0);
+ if (retries == 51) {
+ CX18_ERR("Could not start the CPU\n");
+ return -EIO;
+ }
+ }
+ if (sz <= 0)
+ return -EIO;
+ }
+ /* initialize GPIO */
+ write_reg(0x14001400, 0xC78110);
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h
new file mode 100644
index 000000000000..38d4c05e8499
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-firmware.h
@@ -0,0 +1,25 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_firmware_init(struct cx18 *cx);
+void cx18_halt_firmware(struct cx18 *cx);
+void cx18_init_memory(struct cx18 *cx);
+void cx18_init_power(struct cx18 *cx, int lowpwr);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
new file mode 100644
index 000000000000..bb8bc86086d0
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -0,0 +1,99 @@
+/*
+ * cx18 gpio functions
+ *
+ * Derived from ivtv-gpio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "tuner-xc2028.h"
+
+/********************* GPIO stuffs *********************/
+
+/* GPIO registers */
+#define CX18_REG_GPIO_IN 0xc72010
+#define CX18_REG_GPIO_OUT1 0xc78100
+#define CX18_REG_GPIO_DIR1 0xc78108
+#define CX18_REG_GPIO_OUT2 0xc78104
+#define CX18_REG_GPIO_DIR2 0xc7810c
+
+static u32 gpio_dir;
+static u32 gpio_val;
+
+/*
+ * HVR-1600 GPIO pins, courtesy of Hauppauge:
+ *
+ * gpio0: zilog ir process reset pin
+ * gpio1: zilog programming pin (you should never use this)
+ * gpio12: cx24227 reset pin
+ * gpio13: cs5345 reset pin
+*/
+
+static void gpio_write(struct cx18 *cx)
+{
+ write_reg((gpio_dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+ write_reg(((gpio_dir & 0xffff) << 16) | (gpio_val & 0xffff),
+ CX18_REG_GPIO_OUT1);
+ write_reg(gpio_dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+ write_reg((gpio_dir & 0xffff0000) | ((gpio_val & 0xffff0000) >> 16),
+ CX18_REG_GPIO_OUT2);
+}
+
+void cx18_gpio_init(struct cx18 *cx)
+{
+ gpio_dir = cx->card->gpio_init.direction;
+ gpio_val = cx->card->gpio_init.initial_value;
+
+ if (gpio_dir == 0)
+ return;
+
+ gpio_dir |= 1 << cx->card->xceive_pin;
+ gpio_val |= 1 << cx->card->xceive_pin;
+
+ CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
+ read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
+ read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
+
+ gpio_write(cx);
+}
+
+/* Xceive tuner reset function */
+int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
+{
+ struct i2c_algo_bit_data *algo = dev;
+ struct cx18_i2c_algo_callback_data *cb_data = algo->data;
+ struct cx18 *cx = cb_data->cx;
+
+ if (cmd != XC2028_TUNER_RESET)
+ return 0;
+ CX18_DEBUG_INFO("Resetting tuner\n");
+
+ gpio_dir |= 1 << cx->card->xceive_pin;
+ gpio_val &= ~(1 << cx->card->xceive_pin);
+
+ gpio_write(cx);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
+
+ gpio_val |= 1 << cx->card->xceive_pin;
+ gpio_write(cx);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
new file mode 100644
index 000000000000..41bac8856b50
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -0,0 +1,24 @@
+/*
+ * cx18 gpio functions
+ *
+ * Derived from ivtv-gpio.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+void cx18_gpio_init(struct cx18 *cx);
+int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
new file mode 100644
index 000000000000..1d6c51a75313
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -0,0 +1,431 @@
+/*
+ * cx18 I2C functions
+ *
+ * Derived from ivtv-i2c.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "cx18-av-core.h"
+#include "cx18-i2c.h"
+
+#include <media/ir-kbd-i2c.h>
+
+#define CX18_REG_I2C_1_WR 0xf15000
+#define CX18_REG_I2C_1_RD 0xf15008
+#define CX18_REG_I2C_2_WR 0xf25100
+#define CX18_REG_I2C_2_RD 0xf25108
+
+#define SETSCL_BIT 0x0001
+#define SETSDL_BIT 0x0002
+#define GETSCL_BIT 0x0004
+#define GETSDL_BIT 0x0008
+
+#ifndef I2C_ADAP_CLASS_TV_ANALOG
+#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
+#endif
+
+#define CX18_CS5345_I2C_ADDR 0x4c
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_driverids[] = {
+ I2C_DRIVERID_TUNER,
+ I2C_DRIVERID_TVEEPROM,
+ I2C_DRIVERID_CS5345,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0 /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_addrs[] = {
+ 0,
+ 0,
+ CX18_CS5345_I2C_ADDR,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0, /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+/* This might well become a card-specific array */
+static const u8 hw_bus[] = {
+ 0,
+ 0,
+ 0,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0, /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const char * const hw_devicenames[] = {
+ "tuner",
+ "tveeprom",
+ "cs5345",
+ "gpio",
+ "cx23418",
+};
+
+int cx18_i2c_register(struct cx18 *cx, unsigned idx)
+{
+ struct i2c_board_info info;
+ struct i2c_client *c;
+ u8 id, bus;
+ int i;
+
+ CX18_DEBUG_I2C("i2c client register\n");
+ if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+ return -1;
+ id = hw_driverids[idx];
+ bus = hw_bus[idx];
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
+ info.addr = hw_addrs[idx];
+ for (i = 0; i < I2C_CLIENTS_MAX; i++)
+ if (cx->i2c_clients[i] == NULL)
+ break;
+
+ if (i == I2C_CLIENTS_MAX) {
+ CX18_ERR("insufficient room for new I2C client!\n");
+ return -ENOMEM;
+ }
+
+ if (id != I2C_DRIVERID_TUNER) {
+ c = i2c_new_device(&cx->i2c_adap[bus], &info);
+ if (c->driver == NULL)
+ i2c_unregister_device(c);
+ else
+ cx->i2c_clients[i] = c;
+ return cx->i2c_clients[i] ? 0 : -ENODEV;
+ }
+
+ /* special tuner handling */
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ return 0;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ int i;
+ struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
+
+ CX18_DEBUG_I2C("i2c client detach\n");
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ if (cx->i2c_clients[i] == client) {
+ cx->i2c_clients[i] = NULL;
+ break;
+ }
+ }
+ CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n",
+ client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
+
+ return 0;
+}
+
+static void cx18_setscl(void *data, int state)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+ u32 r = read_reg(addr);
+
+ if (state)
+ write_reg_sync(r | SETSCL_BIT, addr);
+ else
+ write_reg_sync(r & ~SETSCL_BIT, addr);
+}
+
+static void cx18_setsda(void *data, int state)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+ u32 r = read_reg(addr);
+
+ if (state)
+ write_reg_sync(r | SETSDL_BIT, addr);
+ else
+ write_reg_sync(r & ~SETSDL_BIT, addr);
+}
+
+static int cx18_getscl(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+ return read_reg(addr) & GETSCL_BIT;
+}
+
+static int cx18_getsda(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+ return read_reg(addr) & GETSDL_BIT;
+}
+
+/* template for i2c-bit-algo */
+static struct i2c_adapter cx18_i2c_adap_template = {
+ .name = "cx18 i2c driver",
+ .id = I2C_HW_B_CX2341X,
+ .algo = NULL, /* set by i2c-algo-bit */
+ .algo_data = NULL, /* filled from template */
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+ .owner = THIS_MODULE,
+};
+
+#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
+#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
+
+static struct i2c_algo_bit_data cx18_i2c_algo_template = {
+ .setsda = cx18_setsda,
+ .setscl = cx18_setscl,
+ .getsda = cx18_getsda,
+ .getscl = cx18_getscl,
+ .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/
+ .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
+};
+
+static struct i2c_client cx18_i2c_client_template = {
+ .name = "cx18 internal",
+};
+
+int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
+{
+ struct i2c_client *client;
+ int retval;
+ int i;
+
+ CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ client = cx->i2c_clients[i];
+ if (client == NULL || client->driver == NULL ||
+ client->driver->command == NULL)
+ continue;
+ if (addr == client->addr) {
+ retval = client->driver->command(client, cmd, arg);
+ return retval;
+ }
+ }
+ if (cmd != VIDIOC_G_CHIP_IDENT)
+ CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
+ addr, cmd);
+ return -ENODEV;
+}
+
+/* Find the i2c device based on the driver ID and return
+ its i2c address or -ENODEV if no matching device was found. */
+static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
+{
+ struct i2c_client *client;
+ int retval = -ENODEV;
+ int i;
+
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ client = cx->i2c_clients[i];
+ if (client == NULL || client->driver == NULL)
+ continue;
+ if (id == client->driver->id) {
+ retval = client->addr;
+ break;
+ }
+ }
+ return retval;
+}
+
+/* Find the i2c device name matching the DRIVERID */
+static const char *cx18_i2c_id_name(u32 id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (hw_driverids[i] == id)
+ return hw_devicenames[i];
+ return "unknown device";
+}
+
+/* Find the i2c device name matching the CX18_HW_ flag */
+static const char *cx18_i2c_hw_name(u32 hw)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (1 << i == hw)
+ return hw_devicenames[i];
+ return "unknown device";
+}
+
+/* Find the i2c device matching the CX18_HW_ flag and return
+ its i2c address or -ENODEV if no matching device was found. */
+int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (1 << i == hw)
+ return cx18_i2c_id_addr(cx, hw_driverids[i]);
+ return -ENODEV;
+}
+
+/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing.
+ If hw == CX18_HW_GPIO then call the gpio handler. */
+int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
+{
+ int addr;
+
+ if (hw == CX18_HW_GPIO || hw == 0)
+ return 0;
+ if (hw == CX18_HW_CX23418)
+ return cx18_av_cmd(cx, cmd, arg);
+
+ addr = cx18_i2c_hw_addr(cx, hw);
+ if (addr < 0) {
+ CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n",
+ hw, cx18_i2c_hw_name(hw), cmd);
+ return addr;
+ }
+ return cx18_call_i2c_client(cx, addr, cmd, arg);
+}
+
+/* Calls i2c device based on I2C driver ID. */
+int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg)
+{
+ int addr;
+
+ addr = cx18_i2c_id_addr(cx, id);
+ if (addr < 0) {
+ if (cmd != VIDIOC_G_CHIP_IDENT)
+ CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n",
+ id, cx18_i2c_id_name(id), cmd);
+ return addr;
+ }
+ return cx18_call_i2c_client(cx, addr, cmd, arg);
+}
+
+/* broadcast cmd for all I2C clients and for the gpio subsystem */
+void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) {
+ CX18_ERR("adapter is not set\n");
+ return;
+ }
+ cx18_av_cmd(cx, cmd, arg);
+ i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
+ i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+}
+
+/* init + register i2c algo-bit adapter */
+int init_cx18_i2c(struct cx18 *cx)
+{
+ int i;
+ CX18_DEBUG_I2C("i2c init\n");
+
+ for (i = 0; i < 2; i++) {
+ memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
+ sizeof(struct i2c_adapter));
+ memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
+ sizeof(struct i2c_algo_bit_data));
+ cx->i2c_algo_cb_data[i].cx = cx;
+ cx->i2c_algo_cb_data[i].bus_index = i;
+ cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
+ cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
+
+ sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
+ " #%d-%d", cx->num, i);
+ i2c_set_adapdata(&cx->i2c_adap[i], cx);
+
+ memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
+ sizeof(struct i2c_client));
+ sprintf(cx->i2c_client[i].name +
+ strlen(cx->i2c_client[i].name), "%d", i);
+ cx->i2c_client[i].adapter = &cx->i2c_adap[i];
+ cx->i2c_adap[i].dev.parent = &cx->dev->dev;
+ }
+
+ if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
+ /* Reset/Unreset I2C hardware block */
+ write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
+ write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
+ }
+ /* courtesy of Steven Toth <stoth@hauppauge.com> */
+ write_reg_sync(0x00c00000, 0xc7001c);
+ mdelay(10);
+ write_reg_sync(0x00c000c0, 0xc7001c);
+ mdelay(10);
+ write_reg_sync(0x00c00000, 0xc7001c);
+
+ write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
+ write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
+
+ /* Hw I2C1 Clock Freq ~100kHz */
+ write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+ cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
+
+ /* Hw I2C2 Clock Freq ~100kHz */
+ write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+ cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+
+ return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
+ i2c_bit_add_bus(&cx->i2c_adap[1]);
+}
+
+void exit_cx18_i2c(struct cx18 *cx)
+{
+ int i;
+ CX18_DEBUG_I2C("i2c exit\n");
+ write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
+ write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
+
+ for (i = 0; i < 2; i++) {
+ i2c_del_adapter(&cx->i2c_adap[i]);
+ }
+}
+
+/*
+ Hauppauge HVR1600 should have:
+ 32 cx24227
+ 98 unknown
+ a0 eeprom
+ c2 tuner
+ e? zilog ir
+ */
diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h
new file mode 100644
index 000000000000..113c3f9a2cc0
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-i2c.h
@@ -0,0 +1,33 @@
+/*
+ * cx18 I2C functions
+ *
+ * Derived from ivtv-i2c.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
+int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
+int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg);
+int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
+void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_i2c_register(struct cx18 *cx, unsigned idx);
+
+/* init + register i2c algo-bit adapter */
+int init_cx18_i2c(struct cx18 *cx);
+void exit_cx18_i2c(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
new file mode 100644
index 000000000000..dbdcb86ec5aa
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -0,0 +1,851 @@
+/*
+ * cx18 ioctl system call
+ *
+ * Derived from ivtv-ioctl.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-fileops.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-video.h"
+#include "cx18-streams.h"
+#include "cx18-ioctl.h"
+#include "cx18-gpio.h"
+#include "cx18-controls.h"
+#include "cx18-cards.h"
+#include "cx18-av-core.h"
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/i2c-id.h>
+
+u16 cx18_service2vbi(int type)
+{
+ switch (type) {
+ case V4L2_SLICED_TELETEXT_B:
+ return CX18_SLICED_TYPE_TELETEXT_B;
+ case V4L2_SLICED_CAPTION_525:
+ return CX18_SLICED_TYPE_CAPTION_525;
+ case V4L2_SLICED_WSS_625:
+ return CX18_SLICED_TYPE_WSS_625;
+ case V4L2_SLICED_VPS:
+ return CX18_SLICED_TYPE_VPS;
+ default:
+ return 0;
+ }
+}
+
+static int valid_service_line(int field, int line, int is_pal)
+{
+ return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+ (!is_pal && line >= 10 && line < 22);
+}
+
+static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+{
+ u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+ int i;
+
+ set = set & valid_set;
+ if (set == 0 || !valid_service_line(field, line, is_pal))
+ return 0;
+ if (!is_pal) {
+ if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
+ return V4L2_SLICED_CAPTION_525;
+ } else {
+ if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
+ return V4L2_SLICED_VPS;
+ if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
+ return V4L2_SLICED_WSS_625;
+ if (line == 23)
+ return 0;
+ }
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) & set)
+ return 1 << i;
+ }
+ return 0;
+}
+
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+ u16 set = fmt->service_set;
+ int f, l;
+
+ fmt->service_set = 0;
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++)
+ fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
+ }
+}
+
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+ int f, l;
+ u16 set = 0;
+
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+ set |= fmt->service_lines[f][l];
+ }
+ }
+ return set != 0;
+}
+
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
+{
+ int f, l;
+ u16 set = 0;
+
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++)
+ set |= fmt->service_lines[f][l];
+ }
+ return set;
+}
+
+static const struct {
+ v4l2_std_id std;
+ char *name;
+} enum_stds[] = {
+ { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
+ { V4L2_STD_PAL_DK, "PAL-DK" },
+ { V4L2_STD_PAL_I, "PAL-I" },
+ { V4L2_STD_PAL_M, "PAL-M" },
+ { V4L2_STD_PAL_N, "PAL-N" },
+ { V4L2_STD_PAL_Nc, "PAL-Nc" },
+ { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
+ { V4L2_STD_SECAM_DK, "SECAM-DK" },
+ { V4L2_STD_SECAM_L, "SECAM-L" },
+ { V4L2_STD_SECAM_LC, "SECAM-L'" },
+ { V4L2_STD_NTSC_M, "NTSC-M" },
+ { V4L2_STD_NTSC_M_JP, "NTSC-J" },
+ { V4L2_STD_NTSC_M_KR, "NTSC-K" },
+};
+
+static const struct v4l2_standard cx18_std_60hz = {
+ .frameperiod = {.numerator = 1001, .denominator = 30000},
+ .framelines = 525,
+};
+
+static const struct v4l2_standard cx18_std_50hz = {
+ .frameperiod = { .numerator = 1, .denominator = 25 },
+ .framelines = 625,
+};
+
+static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_register *regs = arg;
+ unsigned long flags;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cx18_cards_lock, flags);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ regs->val = read_enc(regs->reg);
+ else
+ write_enc(regs->val, regs->reg);
+ spin_unlock_irqrestore(&cx18_cards_lock, flags);
+ return 0;
+}
+
+static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ fmt->fmt.pix.width = cx->params.width;
+ fmt->fmt.pix.height = cx->params.height;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ fmt->fmt.pix.sizeimage =
+ fmt->fmt.pix.height * fmt->fmt.pix.width +
+ fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+ } else {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ fmt->fmt.pix.sizeimage = 128 * 1024;
+ }
+ break;
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ fmt->fmt.vbi.sampling_rate = 27000000;
+ fmt->fmt.vbi.offset = 248;
+ fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+ fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ fmt->fmt.vbi.start[0] = cx->vbi.start[0];
+ fmt->fmt.vbi.start[1] = cx->vbi.start[1];
+ fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ {
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+ memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+
+ cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
+ struct v4l2_format *fmt, int set_fmt)
+{
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ u16 set;
+
+ /* set window size */
+ if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ if (w > 720)
+ w = 720;
+ else if (w < 1)
+ w = 1;
+ if (h > (cx->is_50hz ? 576 : 480))
+ h = (cx->is_50hz ? 576 : 480);
+ else if (h < 2)
+ h = 2;
+ cx18_get_fmt(cx, streamtype, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+
+ if (!set_fmt || (cx->params.width == w && cx->params.height == h))
+ return 0;
+ if (atomic_read(&cx->capturing) > 0)
+ return -EBUSY;
+
+ cx->params.width = w;
+ cx->params.height = h;
+ if (w != 720 || h != (cx->is_50hz ? 576 : 480))
+ cx->params.video_temporal_filter = 0;
+ else
+ cx->params.video_temporal_filter = 8;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ return cx18_get_fmt(cx, streamtype, fmt);
+ }
+
+ /* set raw VBI format */
+ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set &&
+ atomic_read(&cx->capturing) > 0)
+ return -EBUSY;
+ if (set_fmt) {
+ cx->vbi.sliced_in->service_set = 0;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ }
+ return cx18_get_fmt(cx, streamtype, fmt);
+ }
+
+ /* any else but sliced VBI capture is an error */
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+
+ /* TODO: implement sliced VBI, for now silently return 0 */
+ return 0;
+
+ /* set sliced VBI capture format */
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+
+ if (vbifmt->service_set)
+ cx18_expand_service_set(vbifmt, cx->is_50hz);
+ set = check_service_set(vbifmt, cx->is_50hz);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
+
+ if (!set_fmt)
+ return 0;
+ if (set == 0)
+ return -EINVAL;
+ if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
+ return -EBUSY;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+ return 0;
+}
+
+static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct v4l2_register *reg = arg;
+
+ switch (cmd) {
+ /* ioctls to allow direct access to the encoder registers for testing */
+ case VIDIOC_DBG_G_REGISTER:
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+
+ case VIDIOC_DBG_S_REGISTER:
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+
+ case VIDIOC_G_CHIP_IDENT: {
+ struct v4l2_chip_ident *chip = arg;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
+ struct v4l2_chip_ident *chip = arg;
+
+ chip->ident = V4L2_IDENT_CX23418;
+ }
+ return 0;
+ }
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+ return -EINVAL;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ cx18_audio_set_route(cx, route);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
+{
+ struct cx18_open_id *id = NULL;
+
+ if (filp)
+ id = (struct cx18_open_id *)filp->private_data;
+
+ switch (cmd) {
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+
+ *p = v4l2_prio_max(&cx->prio);
+ break;
+ }
+
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *prio = arg;
+
+ return v4l2_prio_change(&cx->prio, &id->prio, *prio);
+ }
+
+ case VIDIOC_QUERYCAP:{
+ struct v4l2_capability *vcap = arg;
+
+ memset(vcap, 0, sizeof(*vcap));
+ strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+ vcap->version = CX18_DRIVER_VERSION; /* version */
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+
+ /* reserved.. must set to 0! */
+ vcap->reserved[0] = vcap->reserved[1] =
+ vcap->reserved[2] = vcap->reserved[3] = 0;
+ break;
+ }
+
+ case VIDIOC_ENUMAUDIO:{
+ struct v4l2_audio *vin = arg;
+
+ return cx18_get_audio_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_G_AUDIO:{
+ struct v4l2_audio *vin = arg;
+
+ vin->index = cx->audio_input;
+ return cx18_get_audio_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_S_AUDIO:{
+ struct v4l2_audio *vout = arg;
+
+ if (vout->index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ cx->audio_input = vout->index;
+ cx18_audio_set_io(cx);
+ break;
+ }
+
+ case VIDIOC_ENUMINPUT:{
+ struct v4l2_input *vin = arg;
+
+ /* set it to defaults from our table */
+ return cx18_get_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *fmt = arg;
+
+ return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
+ }
+
+ case VIDIOC_G_FMT: {
+ struct v4l2_format *fmt = arg;
+ int type = fmt->type;
+
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->type = type;
+ return cx18_get_fmt(cx, id->type, fmt);
+ }
+
+ case VIDIOC_CROPCAP: {
+ struct v4l2_cropcap *cropcap = arg;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+ cropcap->defrect = cropcap->bounds;
+ return 0;
+ }
+
+ case VIDIOC_S_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
+ }
+
+ case VIDIOC_G_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
+ }
+
+ case VIDIOC_ENUM_FMT: {
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+ { 0, 0, 0, 0 }
+ },
+ { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG,
+ { 0, 0, 0, 0 }
+ }
+ };
+ struct v4l2_fmtdesc *fmt = arg;
+ enum v4l2_buf_type type = fmt->type;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (fmt->index > 1)
+ return -EINVAL;
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:{
+ *(int *)arg = cx->active_input;
+ break;
+ }
+
+ case VIDIOC_S_INPUT:{
+ int inp = *(int *)arg;
+
+ if (inp < 0 || inp >= cx->nof_inputs)
+ return -EINVAL;
+
+ if (inp == cx->active_input) {
+ CX18_DEBUG_INFO("Input unchanged\n");
+ break;
+ }
+ CX18_DEBUG_INFO("Changing input from %d to %d\n",
+ cx->active_input, inp);
+
+ cx->active_input = inp;
+ /* Set the audio input to whatever is appropriate for the
+ input type. */
+ cx->audio_input = cx->card->video_inputs[inp].audio_index;
+
+ /* prevent others from messing with the streams until
+ we're finished changing inputs. */
+ cx18_mute(cx);
+ cx18_video_set_io(cx);
+ cx18_audio_set_io(cx);
+ cx18_unmute(cx);
+ break;
+ }
+
+ case VIDIOC_G_FREQUENCY:{
+ struct v4l2_frequency *vf = arg;
+
+ if (vf->tuner != 0)
+ return -EINVAL;
+ cx18_call_i2c_clients(cx, cmd, arg);
+ break;
+ }
+
+ case VIDIOC_S_FREQUENCY:{
+ struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+
+ if (vf.tuner != 0)
+ return -EINVAL;
+
+ cx18_mute(cx);
+ CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
+ cx18_call_i2c_clients(cx, cmd, &vf);
+ cx18_unmute(cx);
+ break;
+ }
+
+ case VIDIOC_ENUMSTD:{
+ struct v4l2_standard *vs = arg;
+ int idx = vs->index;
+
+ if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
+ return -EINVAL;
+
+ *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
+ cx18_std_60hz : cx18_std_50hz;
+ vs->index = idx;
+ vs->id = enum_stds[idx].std;
+ strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
+ break;
+ }
+
+ case VIDIOC_G_STD:{
+ *(v4l2_std_id *) arg = cx->std;
+ break;
+ }
+
+ case VIDIOC_S_STD: {
+ v4l2_std_id std = *(v4l2_std_id *) arg;
+
+ if ((std & V4L2_STD_ALL) == 0)
+ return -EINVAL;
+
+ if (std == cx->std)
+ break;
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+ atomic_read(&cx->capturing) > 0) {
+ /* Switching standard would turn off the radio or mess
+ with already running streams, prevent that by
+ returning EBUSY. */
+ return -EBUSY;
+ }
+
+ cx->std = std;
+ cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
+ cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+ cx->params.width = 720;
+ cx->params.height = cx->is_50hz ? 576 : 480;
+ cx->vbi.count = cx->is_50hz ? 18 : 12;
+ cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+ cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+ cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+ CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
+
+ /* Tuner */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ break;
+ }
+
+ case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
+ struct v4l2_tuner *vt = arg;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+ break;
+ }
+
+ case VIDIOC_G_TUNER: {
+ struct v4l2_tuner *vt = arg;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ memset(vt, 0, sizeof(*vt));
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_ANALOG_TV;
+ }
+ break;
+ }
+
+ case VIDIOC_G_SLICED_VBI_CAP: {
+ struct v4l2_sliced_vbi_cap *cap = arg;
+ int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+ int f, l;
+ enum v4l2_buf_type type = cap->type;
+
+ memset(cap, 0, sizeof(*cap));
+ cap->type = type;
+ if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ if (valid_service_line(f, l, cx->is_50hz))
+ cap->service_lines[f][l] = set;
+ }
+ }
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD: {
+ struct v4l2_encoder_cmd *enc = arg;
+ int try = cmd == VIDIOC_TRY_ENCODER_CMD;
+
+ memset(&enc->raw, 0, sizeof(enc->raw));
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ return cx18_start_capture(id);
+
+ case V4L2_ENC_CMD_STOP:
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ if (try)
+ return 0;
+ cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+ return 0;
+
+ case V4L2_ENC_CMD_PAUSE:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ if (!atomic_read(&cx->capturing))
+ return -EPERM;
+ if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_mute(cx);
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+ break;
+
+ case V4L2_ENC_CMD_RESUME:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ if (!atomic_read(&cx->capturing))
+ return -EPERM;
+ if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+ cx18_unmute(cx);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ {
+ struct v4l2_input vidin;
+ struct v4l2_audio audin;
+ int i;
+
+ CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
+ if (cx->hw_flags & CX18_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+ }
+ cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+ cx18_get_input(cx, cx->active_input, &vidin);
+ cx18_get_audio_input(cx, cx->audio_input, &audin);
+ CX18_INFO("Video Input: %s\n", vidin.name);
+ CX18_INFO("Audio Input: %s\n", audin.name);
+ CX18_INFO("Tuner: %s\n",
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
+ "Radio" : "TV");
+ cx2341x_log_status(&cx->params, cx->name);
+ CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL || s->buffers == 0)
+ continue;
+ CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+ s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers * s->buf_size) / 1024, s->buffers);
+ }
+ CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+ (long long)cx->mpg_data_received,
+ (long long)cx->vbi_data_inserted);
+ CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, void *arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ int ret;
+
+ /* check priority */
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_S_FMT:
+ case VIDIOC_S_CROP:
+ case VIDIOC_S_EXT_CTRLS:
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+ }
+
+ switch (cmd) {
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ case VIDIOC_INT_RESET:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_debug_ioctls(filp, cmd, arg);
+
+ case VIDIOC_G_PRIORITY:
+ case VIDIOC_S_PRIORITY:
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_ENUMINPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_ENUM_FMT:
+ case VIDIOC_CROPCAP:
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_G_SLICED_VBI_CAP:
+ case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_ENC_INDEX:
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_v4l2_ioctls(cx, filp, cmd, arg);
+
+ case VIDIOC_QUERYMENU:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_control_ioctls(cx, cmd, arg);
+
+ case 0x00005401: /* Handle isatty() calls */
+ return -EINVAL;
+ default:
+ return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+ cx18_v4l2_do_ioctl);
+ }
+ return 0;
+}
+
+int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ int res;
+
+ mutex_lock(&cx->serialize_lock);
+ res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+ mutex_unlock(&cx->serialize_lock);
+ return res;
+}
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
new file mode 100644
index 000000000000..9f4c7eb2897f
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -0,0 +1,30 @@
+/*
+ * cx18 ioctl system call
+ *
+ * Derived from ivtv-ioctl.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+u16 cx18_service2vbi(int type);
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
+ void *arg);
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
new file mode 100644
index 000000000000..6e14f8bda559
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -0,0 +1,179 @@
+/*
+ * cx18 interrupt handling
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-firmware.h"
+#include "cx18-fileops.h"
+#include "cx18-queue.h"
+#include "cx18-irq.h"
+#include "cx18-ioctl.h"
+#include "cx18-mailbox.h"
+#include "cx18-vbi.h"
+#include "cx18-scb.h"
+
+#define DMA_MAGIC_COOKIE 0x000001fe
+
+static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
+{
+ u32 handle = mb->args[0];
+ struct cx18_stream *s = NULL;
+ struct cx18_buffer *buf;
+ u32 off;
+ int i;
+ int id;
+
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ s = &cx->streams[i];
+ if ((handle == s->handle) && (s->dvb.enabled))
+ break;
+ if (s->v4l2dev && handle == s->handle)
+ break;
+ }
+ if (i == CX18_MAX_STREAMS) {
+ CX18_WARN("DMA done for unknown handle %d for stream %s\n",
+ handle, s->name);
+ mb->error = CXERR_NOT_OPEN;
+ mb->cmd = 0;
+ cx18_mb_ack(cx, mb);
+ return;
+ }
+
+ off = mb->args[1];
+ if (mb->args[2] != 1)
+ CX18_WARN("Ack struct = %d for %s\n",
+ mb->args[2], s->name);
+ id = read_enc(off);
+ buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+ CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
+ if (buf) {
+ cx18_buf_sync_for_cpu(s, buf);
+ if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
+ /* process the buffer here */
+ CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
+ buf->bytesused);
+
+ dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+ buf->bytesused);
+
+ cx18_buf_sync_for_device(s, buf);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ } else
+ set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ } else {
+ CX18_WARN("Could not find buf %d for stream %s\n",
+ read_enc(off), s->name);
+ }
+ mb->error = 0;
+ mb->cmd = 0;
+ cx18_mb_ack(cx, mb);
+ wake_up(&cx->dma_waitq);
+ if (s->id != -1)
+ wake_up(&s->waitq);
+}
+
+static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
+{
+ char str[256] = { 0 };
+ char *p;
+
+ if (mb->args[1]) {
+ setup_page(mb->args[1]);
+ memcpy_fromio(str, cx->enc_mem + mb->args[1], 252);
+ str[252] = 0;
+ }
+ cx18_mb_ack(cx, mb);
+ CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
+ p = strchr(str, '.');
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
+ CX18_INFO("FW version: %s\n", p - 1);
+}
+
+static void hpu_cmd(struct cx18 *cx, u32 sw1)
+{
+ struct cx18_mailbox mb;
+
+ if (sw1 & IRQ_CPU_TO_EPU) {
+ memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb));
+ mb.error = 0;
+
+ switch (mb.cmd) {
+ case CX18_EPU_DMA_DONE:
+ epu_dma_done(cx, &mb);
+ break;
+ case CX18_EPU_DEBUG:
+ epu_debug(cx, &mb);
+ break;
+ default:
+ CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd);
+ break;
+ }
+ }
+ if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU))
+ CX18_WARN("Unexpected interrupt %08x\n", sw1);
+}
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id)
+{
+ struct cx18 *cx = (struct cx18 *)dev_id;
+ u32 sw1, sw1_mask;
+ u32 sw2, sw2_mask;
+ u32 hw2, hw2_mask;
+
+ spin_lock(&cx->dma_reg_lock);
+
+ hw2_mask = read_reg(HW2_INT_MASK5_PCI);
+ hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask;
+ sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
+ sw2 = read_reg(SW2_INT_STATUS) & sw2_mask;
+ sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
+ sw1 = read_reg(SW1_INT_STATUS) & sw1_mask;
+
+ write_reg(sw2&sw2_mask, SW2_INT_STATUS);
+ write_reg(sw1&sw1_mask, SW1_INT_STATUS);
+ write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS);
+
+ if (sw1 || sw2 || hw2)
+ CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2);
+
+ /* To do: interrupt-based I2C handling
+ if (hw2 & 0x00c00000) {
+ }
+ */
+
+ if (sw2) {
+ if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack))
+ wake_up(&cx->mb_cpu_waitq);
+ if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack))
+ wake_up(&cx->mb_apu_waitq);
+ if (sw2 & cx->scb->epu2hpu_irq_ack)
+ wake_up(&cx->mb_epu_waitq);
+ if (sw2 & cx->scb->hpu2epu_irq_ack)
+ wake_up(&cx->mb_hpu_waitq);
+ }
+
+ if (sw1)
+ hpu_cmd(cx, sw1);
+ spin_unlock(&cx->dma_reg_lock);
+
+ return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE;
+}
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h
new file mode 100644
index 000000000000..379f704f5cba
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-irq.h
@@ -0,0 +1,37 @@
+/*
+ * cx18 interrupt handling
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 HW2_I2C1_INT (1 << 22)
+#define HW2_I2C2_INT (1 << 23)
+#define HW2_INT_CLR_STATUS 0xc730c4
+#define HW2_INT_MASK5_PCI 0xc730e4
+#define SW1_INT_SET 0xc73100
+#define SW1_INT_STATUS 0xc73104
+#define SW1_INT_ENABLE_PCI 0xc7311c
+#define SW2_INT_SET 0xc73140
+#define SW2_INT_STATUS 0xc73144
+#define SW2_INT_ENABLE_PCI 0xc7315c
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id);
+
+void cx18_irq_work_handler(struct work_struct *work);
+void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
+void cx18_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
new file mode 100644
index 000000000000..0c5f328bca54
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -0,0 +1,372 @@
+/*
+ * cx18 mailbox functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 <stdarg.h>
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-mailbox.h"
+
+#define API_FAST (1 << 2) /* Short timeout */
+#define API_SLOW (1 << 3) /* Additional 300ms timeout */
+
+#define APU 0
+#define CPU 1
+#define EPU 2
+#define HPU 3
+
+struct cx18_api_info {
+ u32 cmd;
+ u8 flags; /* Flags, see above */
+ u8 rpu; /* Processing unit */
+ const char *name; /* The name of the command */
+};
+
+#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
+
+static const struct cx18_api_info api_info[] = {
+ /* MPEG encoder API */
+ API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
+ API_ENTRY(CPU, CX18_EPU_DEBUG, 0),
+ API_ENTRY(CPU, CX18_CREATE_TASK, 0),
+ API_ENTRY(CPU, CX18_DESTROY_TASK, 0),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
+ API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
+ API_ENTRY(0, 0, 0),
+};
+
+static const struct cx18_api_info *find_api_info(u32 cmd)
+{
+ int i;
+
+ for (i = 0; api_info[i].cmd; i++)
+ if (api_info[i].cmd == cmd)
+ return &api_info[i];
+ return NULL;
+}
+
+static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
+ u32 *state, u32 *irq, u32 *req)
+{
+ struct cx18_mailbox *mb = NULL;
+ int wait_count = 0;
+ u32 ack;
+
+ switch (rpu) {
+ case APU:
+ mb = &cx->scb->epu2apu_mb;
+ *state = readl(&cx->scb->apu_state);
+ *irq = readl(&cx->scb->epu2apu_irq);
+ break;
+
+ case CPU:
+ mb = &cx->scb->epu2cpu_mb;
+ *state = readl(&cx->scb->cpu_state);
+ *irq = readl(&cx->scb->epu2cpu_irq);
+ break;
+
+ case HPU:
+ mb = &cx->scb->epu2hpu_mb;
+ *state = readl(&cx->scb->hpu_state);
+ *irq = readl(&cx->scb->epu2hpu_irq);
+ break;
+ }
+
+ if (mb == NULL)
+ return mb;
+
+ do {
+ *req = readl(&mb->request);
+ ack = readl(&mb->ack);
+ wait_count++;
+ } while (*req != ack && wait_count < 600);
+
+ if (*req == ack) {
+ (*req)++;
+ if (*req == 0 || *req == 0xffffffff)
+ *req = 1;
+ return mb;
+ }
+ return NULL;
+}
+
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
+{
+ const struct cx18_api_info *info = find_api_info(mb->cmd);
+ struct cx18_mailbox *ack_mb;
+ u32 ack_irq;
+ u8 rpu = CPU;
+
+ if (info == NULL && mb->cmd) {
+ CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
+ return -EINVAL;
+ }
+ if (info)
+ rpu = info->rpu;
+
+ switch (rpu) {
+ case HPU:
+ ack_irq = IRQ_EPU_TO_HPU_ACK;
+ ack_mb = &cx->scb->hpu2epu_mb;
+ break;
+ case APU:
+ ack_irq = IRQ_EPU_TO_APU_ACK;
+ ack_mb = &cx->scb->apu2epu_mb;
+ break;
+ case CPU:
+ ack_irq = IRQ_EPU_TO_CPU_ACK;
+ ack_mb = &cx->scb->cpu2epu_mb;
+ break;
+ default:
+ CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
+ return -EINVAL;
+ }
+
+ setup_page(SCB_OFFSET);
+ write_sync(mb->request, &ack_mb->ack);
+ write_reg(ack_irq, SW2_INT_SET);
+ return 0;
+}
+
+
+static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+ const struct cx18_api_info *info = find_api_info(cmd);
+ u32 state = 0, irq = 0, req, oldreq, err;
+ struct cx18_mailbox *mb;
+ wait_queue_head_t *waitq;
+ int timeout = 100;
+ int cnt = 0;
+ int sig = 0;
+ int i;
+
+ if (info == NULL) {
+ CX18_WARN("unknown cmd %x\n", cmd);
+ return -EINVAL;
+ }
+
+ if (cmd == CX18_CPU_DE_SET_MDL)
+ CX18_DEBUG_HI_API("%s\n", info->name);
+ else
+ CX18_DEBUG_API("%s\n", info->name);
+ setup_page(SCB_OFFSET);
+ mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
+
+ if (mb == NULL) {
+ CX18_ERR("mb %s busy\n", info->name);
+ return -EBUSY;
+ }
+
+ oldreq = req - 1;
+ writel(cmd, &mb->cmd);
+ for (i = 0; i < args; i++)
+ writel(data[i], &mb->args[i]);
+ writel(0, &mb->error);
+ writel(req, &mb->request);
+
+ switch (info->rpu) {
+ case APU: waitq = &cx->mb_apu_waitq; break;
+ case CPU: waitq = &cx->mb_cpu_waitq; break;
+ case EPU: waitq = &cx->mb_epu_waitq; break;
+ case HPU: waitq = &cx->mb_hpu_waitq; break;
+ default: return -EINVAL;
+ }
+ if (info->flags & API_FAST)
+ timeout /= 2;
+ write_reg(irq, SW1_INT_SET);
+
+ while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
+ if (cnt > 200 && !in_atomic())
+ sig = cx18_msleep_timeout(10, 1);
+ cnt++;
+ }
+ if (sig)
+ return -EINTR;
+ if (cnt == 660) {
+ writel(oldreq, &mb->request);
+ CX18_ERR("mb %s failed\n", info->name);
+ return -EINVAL;
+ }
+ for (i = 0; i < MAX_MB_ARGUMENTS; i++)
+ data[i] = readl(&mb->args[i]);
+ err = readl(&mb->error);
+ if (!in_atomic() && (info->flags & API_SLOW))
+ cx18_msleep_timeout(300, 0);
+ if (err)
+ CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
+ info->name);
+ return err ? -EIO : 0;
+}
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+ int res = cx18_api_call(cx, cmd, args, data);
+
+ /* Allow a single retry, probably already too late though.
+ If there is no free mailbox then that is usually an indication
+ of a more serious problem. */
+ return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
+}
+
+static int cx18_set_filter_param(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ u32 mode;
+ int ret;
+
+ mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
+ ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 1, mode, cx->spatial_strength);
+ mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
+ ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 0, mode, cx->temporal_strength);
+ ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 2, cx->filter_mode >> 2, 0);
+ return ret;
+}
+
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx18 *cx = priv;
+ struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+ switch (cmd) {
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return 0;
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
+ s->handle, 0, 0, 0, 0, data[0]);
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
+ s->handle, data[1], data[0]);
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
+ s->handle, data[0]);
+
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
+ s->handle, data[0], data[1]);
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return 0;
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_MUTE_AUDIO:
+ return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_BIT_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
+ s->handle, data[0], data[1], data[2], data[3]);
+ case CX2341X_ENC_MUTE_VIDEO:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_MISC:
+ return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
+ s->handle, data[0], data[1], data[2]);
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ cx->filter_mode = (data[0] & 3) | (data[1] << 2);
+ return cx18_set_filter_param(s);
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ cx->spatial_strength = data[0];
+ cx->temporal_strength = data[1];
+ return cx18_set_filter_param(s);
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
+ s->handle, data[0], data[1]);
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
+ s->handle, data[0], data[1], data[2], data[3]);
+ }
+ CX18_WARN("Unknown cmd %x\n", cmd);
+ return 0;
+}
+
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
+ u32 cmd, int args, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, args);
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(ap, u32);
+ va_end(ap);
+ return cx18_api(cx, cmd, args, data);
+}
+
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
+{
+ u32 data[MAX_MB_ARGUMENTS];
+ va_list ap;
+ int i;
+
+ if (cx == NULL) {
+ CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
+ return 0;
+ }
+ if (args > MAX_MB_ARGUMENTS) {
+ CX18_ERR("args too big (cmd=%x)\n", cmd);
+ args = MAX_MB_ARGUMENTS;
+ }
+ va_start(ap, args);
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(ap, u32);
+ va_end(ap);
+ return cx18_api(cx, cmd, args, data);
+}
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
new file mode 100644
index 000000000000..d995641536b3
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -0,0 +1,73 @@
+/*
+ * cx18 mailbox functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 _CX18_MAILBOX_H_
+#define _CX18_MAILBOX_H_
+
+/* mailbox max args */
+#define MAX_MB_ARGUMENTS 6
+/* compatibility, should be same as the define in cx2341x.h */
+#define CX2341X_MBOX_MAX_DATA 16
+
+#define MB_RESERVED_HANDLE_0 0
+#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
+
+struct cx18;
+
+/* The cx18_mailbox struct is the mailbox structure which is used for passing
+ messages between processors */
+struct cx18_mailbox {
+ /* The sender sets a handle in 'request' after he fills the command. The
+ 'request' should be different than 'ack'. The sender, also, generates
+ an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the
+ receiver. */
+ u32 request;
+ /* The receiver detects a new command when 'req' is different than 'ack'.
+ He sets 'ack' to the same value as 'req' to clear the command. He, also,
+ generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU
+ is the receiver. */
+ u32 ack;
+ u32 reserved[6];
+ /* 'cmd' identifies the command. The list of these commands are in
+ cx23418.h */
+ u32 cmd;
+ /* Each command can have up to 6 arguments */
+ u32 args[MAX_MB_ARGUMENTS];
+ /* The return code can be one of the codes in the file cx23418.h. If the
+ command is completed successfuly, the error will be ERR_SYS_SUCCESS.
+ If it is pending, the code is ERR_SYS_PENDING. If it failed, the error
+ code would indicate the task from which the error originated and will
+ be one of the errors in cx23418.h. In that case, the following
+ applies ((error & 0xff) != 0).
+ If the command is pending, the return will be passed in a MB from the
+ receiver to the sender. 'req' will be returned in args[0] */
+ u32 error;
+};
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
+ int args, ...);
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA]);
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb);
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
new file mode 100644
index 000000000000..6990b77c6200
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -0,0 +1,272 @@
+/*
+ * cx18 buffer queues
+ *
+ * Derived from ivtv-queue.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-streams.h"
+#include "cx18-queue.h"
+#include "cx18-scb.h"
+
+void cx18_buf_swap(struct cx18_buffer *buf)
+{
+ int i;
+
+ for (i = 0; i < buf->bytesused; i += 4)
+ swab32s((u32 *)(buf->buf + i));
+}
+
+void cx18_queue_init(struct cx18_queue *q)
+{
+ INIT_LIST_HEAD(&q->list);
+ q->buffers = 0;
+ q->length = 0;
+ q->bytesused = 0;
+}
+
+void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ unsigned long flags = 0;
+
+ /* clear the buffer if it is going to be enqueued to the free queue */
+ if (q == &s->q_free) {
+ buf->bytesused = 0;
+ buf->readpos = 0;
+ buf->b_flags = 0;
+ }
+ spin_lock_irqsave(&s->qlock, flags);
+ list_add_tail(&buf->list, &q->list);
+ q->buffers++;
+ q->length += s->buf_size;
+ q->bytesused += buf->bytesused - buf->readpos;
+ spin_unlock_irqrestore(&s->qlock, flags);
+}
+
+struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
+{
+ struct cx18_buffer *buf = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&s->qlock, flags);
+ if (!list_empty(&q->list)) {
+ buf = list_entry(q->list.next, struct cx18_buffer, list);
+ list_del_init(q->list.next);
+ q->buffers--;
+ q->length -= s->buf_size;
+ q->bytesused -= buf->bytesused - buf->readpos;
+ }
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return buf;
+}
+
+struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+ u32 bytesused)
+{
+ struct cx18 *cx = s->cx;
+ struct list_head *p;
+
+ list_for_each(p, &s->q_free.list) {
+ struct cx18_buffer *buf =
+ list_entry(p, struct cx18_buffer, list);
+
+ if (buf->id != id)
+ continue;
+ buf->bytesused = bytesused;
+ /* the transport buffers are handled differently,
+ so there is no need to move them to the full queue */
+ if (s->type == CX18_ENC_STREAM_TYPE_TS)
+ return buf;
+ s->q_free.buffers--;
+ s->q_free.length -= s->buf_size;
+ s->q_full.buffers++;
+ s->q_full.length += s->buf_size;
+ s->q_full.bytesused += buf->bytesused;
+ list_move_tail(&buf->list, &s->q_full.list);
+ return buf;
+ }
+ CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
+ return NULL;
+}
+
+static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *to, int clear, int full)
+{
+ struct cx18_buffer *buf =
+ list_entry(from->list.next, struct cx18_buffer, list);
+
+ list_move_tail(from->list.next, &to->list);
+ from->buffers--;
+ from->length -= s->buf_size;
+ from->bytesused -= buf->bytesused - buf->readpos;
+ /* special handling for q_free */
+ if (clear)
+ buf->bytesused = buf->readpos = buf->b_flags = 0;
+ else if (full) {
+ /* special handling for stolen buffers, assume
+ all bytes are used. */
+ buf->bytesused = s->buf_size;
+ buf->readpos = buf->b_flags = 0;
+ }
+ to->buffers++;
+ to->length += s->buf_size;
+ to->bytesused += buf->bytesused - buf->readpos;
+}
+
+/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
+ If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
+ If 'steal' != NULL, then buffers may also taken from that queue if
+ needed.
+
+ The buffer is automatically cleared if it goes to the free queue. It is
+ also cleared if buffers need to be taken from the 'steal' queue and
+ the 'from' queue is the free queue.
+
+ When 'from' is q_free, then needed_bytes is compared to the total
+ available buffer length, otherwise needed_bytes is compared to the
+ bytesused value. For the 'steal' queue the total available buffer
+ length is always used.
+
+ -ENOMEM is returned if the buffers could not be obtained, 0 if all
+ buffers where obtained from the 'from' list and if non-zero then
+ the number of stolen buffers is returned. */
+static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *steal, struct cx18_queue *to,
+ int needed_bytes)
+{
+ unsigned long flags;
+ int rc = 0;
+ int from_free = from == &s->q_free;
+ int to_free = to == &s->q_free;
+ int bytes_available;
+
+ spin_lock_irqsave(&s->qlock, flags);
+ if (needed_bytes == 0) {
+ from_free = 1;
+ needed_bytes = from->length;
+ }
+
+ bytes_available = from_free ? from->length : from->bytesused;
+ bytes_available += steal ? steal->length : 0;
+
+ if (bytes_available < needed_bytes) {
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return -ENOMEM;
+ }
+ if (from_free) {
+ u32 old_length = to->length;
+
+ while (to->length - old_length < needed_bytes) {
+ if (list_empty(&from->list))
+ from = steal;
+ if (from == steal)
+ rc++; /* keep track of 'stolen' buffers */
+ cx18_queue_move_buf(s, from, to, 1, 0);
+ }
+ } else {
+ u32 old_bytesused = to->bytesused;
+
+ while (to->bytesused - old_bytesused < needed_bytes) {
+ if (list_empty(&from->list))
+ from = steal;
+ if (from == steal)
+ rc++; /* keep track of 'stolen' buffers */
+ cx18_queue_move_buf(s, from, to, to_free, rc);
+ }
+ }
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return rc;
+}
+
+void cx18_flush_queues(struct cx18_stream *s)
+{
+ cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
+ cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+}
+
+int cx18_stream_alloc(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ int i;
+
+ if (s->buffers == 0)
+ return 0;
+
+ CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n",
+ s->name, s->buffers, s->buf_size,
+ s->buffers * s->buf_size / 1024);
+
+ if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+ (char *)cx->scb) > SCB_RESERVED_SIZE) {
+ unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
+ ((char *)cx->scb->cpu_mdl));
+
+ CX18_ERR("Too many buffers, cannot fit in SCB area\n");
+ CX18_ERR("Max buffers = %zd\n",
+ bufsz / sizeof(struct cx18_mdl));
+ return -ENOMEM;
+ }
+
+ s->mdl_offset = cx->mdl_offset;
+
+ /* allocate stream buffers. Initially all buffers are in q_free. */
+ for (i = 0; i < s->buffers; i++) {
+ struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer),
+ GFP_KERNEL|__GFP_NOWARN);
+
+ if (buf == NULL)
+ break;
+ buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN);
+ if (buf->buf == NULL) {
+ kfree(buf);
+ break;
+ }
+ buf->id = cx->buffer_id++;
+ INIT_LIST_HEAD(&buf->list);
+ buf->dma_handle = pci_map_single(s->cx->dev,
+ buf->buf, s->buf_size, s->dma);
+ cx18_buf_sync_for_cpu(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+ }
+ if (i == s->buffers) {
+ cx->mdl_offset += s->buffers;
+ return 0;
+ }
+ CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name);
+ cx18_stream_free(s);
+ return -ENOMEM;
+}
+
+void cx18_stream_free(struct cx18_stream *s)
+{
+ struct cx18_buffer *buf;
+
+ /* move all buffers to q_free */
+ cx18_flush_queues(s);
+
+ /* empty q_free */
+ while ((buf = cx18_dequeue(s, &s->q_free))) {
+ pci_unmap_single(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+ kfree(buf->buf);
+ kfree(buf);
+ }
+}
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
new file mode 100644
index 000000000000..91423b9863a4
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -0,0 +1,55 @@
+/*
+ * cx18 buffer queues
+ *
+ * Derived from ivtv-queue.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 CX18_DMA_UNMAPPED ((u32) -1)
+
+/* cx18_buffer utility functions */
+
+static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+}
+
+static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+}
+
+void cx18_buf_swap(struct cx18_buffer *buf);
+
+/* cx18_queue utility functions */
+void cx18_queue_init(struct cx18_queue *q);
+void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q);
+struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
+struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+ u32 bytesused);
+void cx18_flush_queues(struct cx18_stream *s);
+
+/* cx18_stream utility functions */
+int cx18_stream_alloc(struct cx18_stream *s);
+void cx18_stream_free(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
new file mode 100644
index 000000000000..30bc803e30da
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -0,0 +1,121 @@
+/*
+ * cx18 System Control Block initialization
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-scb.h"
+
+void cx18_init_scb(struct cx18 *cx)
+{
+ setup_page(SCB_OFFSET);
+ memset_io(cx->scb, 0, 0x10000);
+
+ writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq);
+ writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
+ writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq);
+ writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq);
+ writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq);
+ writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq);
+ writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
+ writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq);
+ writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq);
+ writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq);
+ writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq);
+ writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
+ writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq);
+ writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
+ writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq);
+ writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq);
+ writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq);
+ writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
+ writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq);
+ writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
+ writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq);
+ writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
+ writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq);
+ writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq);
+ writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
+ writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq);
+ writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
+ writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq);
+ writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq);
+ writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
+
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
+ &cx->scb->apu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
+ &cx->scb->hpu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
+ &cx->scb->ppu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
+ &cx->scb->epu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
+ &cx->scb->cpu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
+ &cx->scb->hpu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
+ &cx->scb->ppu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
+ &cx->scb->epu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
+ &cx->scb->cpu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
+ &cx->scb->apu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
+ &cx->scb->ppu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
+ &cx->scb->epu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
+ &cx->scb->cpu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
+ &cx->scb->apu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
+ &cx->scb->hpu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
+ &cx->scb->epu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
+ &cx->scb->cpu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
+ &cx->scb->apu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
+ &cx->scb->hpu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
+ &cx->scb->ppu2epu_mb_offset);
+
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
+ &cx->scb->ipc_offset);
+
+ writel(1, &cx->scb->hpu_state);
+ writel(1, &cx->scb->epu_state);
+}
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h
new file mode 100644
index 000000000000..86b4cb15d163
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-scb.h
@@ -0,0 +1,285 @@
+/*
+ * cx18 System Control Block initialization
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 CX18_SCB_H
+#define CX18_SCB_H
+
+#include "cx18-mailbox.h"
+
+/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts
+ are in the SW1 register. */
+
+#define IRQ_APU_TO_CPU 0x00000001
+#define IRQ_CPU_TO_APU_ACK 0x00000001
+#define IRQ_HPU_TO_CPU 0x00000002
+#define IRQ_CPU_TO_HPU_ACK 0x00000002
+#define IRQ_PPU_TO_CPU 0x00000004
+#define IRQ_CPU_TO_PPU_ACK 0x00000004
+#define IRQ_EPU_TO_CPU 0x00000008
+#define IRQ_CPU_TO_EPU_ACK 0x00000008
+
+#define IRQ_CPU_TO_APU 0x00000010
+#define IRQ_APU_TO_CPU_ACK 0x00000010
+#define IRQ_HPU_TO_APU 0x00000020
+#define IRQ_APU_TO_HPU_ACK 0x00000020
+#define IRQ_PPU_TO_APU 0x00000040
+#define IRQ_APU_TO_PPU_ACK 0x00000040
+#define IRQ_EPU_TO_APU 0x00000080
+#define IRQ_APU_TO_EPU_ACK 0x00000080
+
+#define IRQ_CPU_TO_HPU 0x00000100
+#define IRQ_HPU_TO_CPU_ACK 0x00000100
+#define IRQ_APU_TO_HPU 0x00000200
+#define IRQ_HPU_TO_APU_ACK 0x00000200
+#define IRQ_PPU_TO_HPU 0x00000400
+#define IRQ_HPU_TO_PPU_ACK 0x00000400
+#define IRQ_EPU_TO_HPU 0x00000800
+#define IRQ_HPU_TO_EPU_ACK 0x00000800
+
+#define IRQ_CPU_TO_PPU 0x00001000
+#define IRQ_PPU_TO_CPU_ACK 0x00001000
+#define IRQ_APU_TO_PPU 0x00002000
+#define IRQ_PPU_TO_APU_ACK 0x00002000
+#define IRQ_HPU_TO_PPU 0x00004000
+#define IRQ_PPU_TO_HPU_ACK 0x00004000
+#define IRQ_EPU_TO_PPU 0x00008000
+#define IRQ_PPU_TO_EPU_ACK 0x00008000
+
+#define IRQ_CPU_TO_EPU 0x00010000
+#define IRQ_EPU_TO_CPU_ACK 0x00010000
+#define IRQ_APU_TO_EPU 0x00020000
+#define IRQ_EPU_TO_APU_ACK 0x00020000
+#define IRQ_HPU_TO_EPU 0x00040000
+#define IRQ_EPU_TO_HPU_ACK 0x00040000
+#define IRQ_PPU_TO_EPU 0x00080000
+#define IRQ_EPU_TO_PPU_ACK 0x00080000
+
+#define SCB_OFFSET 0xDC0000
+
+/* If Firmware uses fixed memory map, it shall not allocate the area
+ between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */
+#define SCB_RESERVED_SIZE 0x10000
+
+
+/* This structure is used by EPU to provide memory descriptors in its memory */
+struct cx18_mdl {
+ u32 paddr; /* Physical address of a buffer segment */
+ u32 length; /* Length of the buffer segment */
+};
+
+/* This structure is used by CPU to provide completed buffers information */
+struct cx18_mdl_ack {
+ u32 id; /* ID of a completed MDL */
+ u32 data_used; /* Total data filled in the MDL for buffer 'id' */
+};
+
+struct cx18_scb {
+ /* These fields form the System Control Block which is used at boot time
+ for localizing the IPC data as well as the code positions for all
+ processors. The offsets are from the start of this struct. */
+
+ /* Offset where to find the Inter-Processor Communication data */
+ u32 ipc_offset;
+ u32 reserved01[7];
+ /* Offset where to find the start of the CPU code */
+ u32 cpu_code_offset;
+ u32 reserved02[3];
+ /* Offset where to find the start of the APU code */
+ u32 apu_code_offset;
+ u32 reserved03[3];
+ /* Offset where to find the start of the HPU code */
+ u32 hpu_code_offset;
+ u32 reserved04[3];
+ /* Offset where to find the start of the PPU code */
+ u32 ppu_code_offset;
+ u32 reserved05[3];
+
+ /* These fields form Inter-Processor Communication data which is used
+ by all processors to locate the information needed for communicating
+ with other processors */
+
+ /* Fields for CPU: */
+
+ /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */
+ u32 cpu_state;
+ u32 reserved1[7];
+ /* Offset to the mailbox used for sending commands from APU to CPU */
+ u32 apu2cpu_mb_offset;
+ /* Value to write to register SW1 register set (0xC7003100) after the
+ command is ready */
+ u32 apu2cpu_irq;
+ /* Value to write to register SW2 register set (0xC7003140) after the
+ command is cleared */
+ u32 apu2cpu_irq_ack;
+ u32 reserved2[13];
+
+ u32 hpu2cpu_mb_offset;
+ u32 hpu2cpu_irq;
+ u32 hpu2cpu_irq_ack;
+ u32 reserved3[13];
+
+ u32 ppu2cpu_mb_offset;
+ u32 ppu2cpu_irq;
+ u32 ppu2cpu_irq_ack;
+ u32 reserved4[13];
+
+ u32 epu2cpu_mb_offset;
+ u32 epu2cpu_irq;
+ u32 epu2cpu_irq_ack;
+ u32 reserved5[13];
+ u32 reserved6[8];
+
+ /* Fields for APU: */
+
+ u32 apu_state;
+ u32 reserved11[7];
+ u32 cpu2apu_mb_offset;
+ u32 cpu2apu_irq;
+ u32 cpu2apu_irq_ack;
+ u32 reserved12[13];
+
+ u32 hpu2apu_mb_offset;
+ u32 hpu2apu_irq;
+ u32 hpu2apu_irq_ack;
+ u32 reserved13[13];
+
+ u32 ppu2apu_mb_offset;
+ u32 ppu2apu_irq;
+ u32 ppu2apu_irq_ack;
+ u32 reserved14[13];
+
+ u32 epu2apu_mb_offset;
+ u32 epu2apu_irq;
+ u32 epu2apu_irq_ack;
+ u32 reserved15[13];
+ u32 reserved16[8];
+
+ /* Fields for HPU: */
+
+ u32 hpu_state;
+ u32 reserved21[7];
+ u32 cpu2hpu_mb_offset;
+ u32 cpu2hpu_irq;
+ u32 cpu2hpu_irq_ack;
+ u32 reserved22[13];
+
+ u32 apu2hpu_mb_offset;
+ u32 apu2hpu_irq;
+ u32 apu2hpu_irq_ack;
+ u32 reserved23[13];
+
+ u32 ppu2hpu_mb_offset;
+ u32 ppu2hpu_irq;
+ u32 ppu2hpu_irq_ack;
+ u32 reserved24[13];
+
+ u32 epu2hpu_mb_offset;
+ u32 epu2hpu_irq;
+ u32 epu2hpu_irq_ack;
+ u32 reserved25[13];
+ u32 reserved26[8];
+
+ /* Fields for PPU: */
+
+ u32 ppu_state;
+ u32 reserved31[7];
+ u32 cpu2ppu_mb_offset;
+ u32 cpu2ppu_irq;
+ u32 cpu2ppu_irq_ack;
+ u32 reserved32[13];
+
+ u32 apu2ppu_mb_offset;
+ u32 apu2ppu_irq;
+ u32 apu2ppu_irq_ack;
+ u32 reserved33[13];
+
+ u32 hpu2ppu_mb_offset;
+ u32 hpu2ppu_irq;
+ u32 hpu2ppu_irq_ack;
+ u32 reserved34[13];
+
+ u32 epu2ppu_mb_offset;
+ u32 epu2ppu_irq;
+ u32 epu2ppu_irq_ack;
+ u32 reserved35[13];
+ u32 reserved36[8];
+
+ /* Fields for EPU: */
+
+ u32 epu_state;
+ u32 reserved41[7];
+ u32 cpu2epu_mb_offset;
+ u32 cpu2epu_irq;
+ u32 cpu2epu_irq_ack;
+ u32 reserved42[13];
+
+ u32 apu2epu_mb_offset;
+ u32 apu2epu_irq;
+ u32 apu2epu_irq_ack;
+ u32 reserved43[13];
+
+ u32 hpu2epu_mb_offset;
+ u32 hpu2epu_irq;
+ u32 hpu2epu_irq_ack;
+ u32 reserved44[13];
+
+ u32 ppu2epu_mb_offset;
+ u32 ppu2epu_irq;
+ u32 ppu2epu_irq_ack;
+ u32 reserved45[13];
+ u32 reserved46[8];
+
+ u32 semaphores[8]; /* Semaphores */
+
+ u32 reserved50[32]; /* Reserved for future use */
+
+ struct cx18_mailbox apu2cpu_mb;
+ struct cx18_mailbox hpu2cpu_mb;
+ struct cx18_mailbox ppu2cpu_mb;
+ struct cx18_mailbox epu2cpu_mb;
+
+ struct cx18_mailbox cpu2apu_mb;
+ struct cx18_mailbox hpu2apu_mb;
+ struct cx18_mailbox ppu2apu_mb;
+ struct cx18_mailbox epu2apu_mb;
+
+ struct cx18_mailbox cpu2hpu_mb;
+ struct cx18_mailbox apu2hpu_mb;
+ struct cx18_mailbox ppu2hpu_mb;
+ struct cx18_mailbox epu2hpu_mb;
+
+ struct cx18_mailbox cpu2ppu_mb;
+ struct cx18_mailbox apu2ppu_mb;
+ struct cx18_mailbox hpu2ppu_mb;
+ struct cx18_mailbox epu2ppu_mb;
+
+ struct cx18_mailbox cpu2epu_mb;
+ struct cx18_mailbox apu2epu_mb;
+ struct cx18_mailbox hpu2epu_mb;
+ struct cx18_mailbox ppu2epu_mb;
+
+ struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2];
+ struct cx18_mdl cpu_mdl[1];
+};
+
+void cx18_init_scb(struct cx18 *cx);
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
new file mode 100644
index 000000000000..4ca9d847f1b1
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -0,0 +1,569 @@
+/*
+ * cx18 init/start/stop/exit stream functions
+ *
+ * Derived from ivtv-streams.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-ioctl.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "cx18-scb.h"
+#include "cx18-av-core.h"
+#include "cx18-dvb.h"
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+static struct file_operations cx18_v4l2_enc_fops = {
+ .owner = THIS_MODULE,
+ .read = cx18_v4l2_read,
+ .open = cx18_v4l2_open,
+ .ioctl = cx18_v4l2_ioctl,
+ .release = cx18_v4l2_close,
+ .poll = cx18_v4l2_enc_poll,
+};
+
+/* offset from 0 to register ts v4l2 minors on */
+#define CX18_V4L2_ENC_TS_OFFSET 16
+/* offset from 0 to register pcm v4l2 minors on */
+#define CX18_V4L2_ENC_PCM_OFFSET 24
+/* offset from 0 to register yuv v4l2 minors on */
+#define CX18_V4L2_ENC_YUV_OFFSET 32
+
+static struct {
+ const char *name;
+ int vfl_type;
+ int minor_offset;
+ int dma;
+ enum v4l2_buf_type buf_type;
+ struct file_operations *fops;
+} cx18_stream_info[] = {
+ { /* CX18_ENC_STREAM_TYPE_MPG */
+ "encoder MPEG",
+ VFL_TYPE_GRABBER, 0,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_TS */
+ "TS",
+ VFL_TYPE_GRABBER, -1,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_YUV */
+ "encoder YUV",
+ VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_VBI */
+ "encoder VBI",
+ VFL_TYPE_VBI, 0,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_PCM */
+ "encoder PCM audio",
+ VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_IDX */
+ "encoder IDX",
+ VFL_TYPE_GRABBER, -1,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_RAD */
+ "encoder radio",
+ VFL_TYPE_RADIO, 0,
+ PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE,
+ &cx18_v4l2_enc_fops
+ },
+};
+
+static void cx18_stream_init(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ struct video_device *dev = s->v4l2dev;
+ u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
+
+ /* we need to keep v4l2dev, so restore it afterwards */
+ memset(s, 0, sizeof(*s));
+ s->v4l2dev = dev;
+
+ /* initialize cx18_stream fields */
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+ s->handle = 0xffffffff;
+
+ s->dma = cx18_stream_info[type].dma;
+ s->buf_size = cx->stream_buf_size[type];
+ if (s->buf_size)
+ s->buffers = max_size / s->buf_size;
+ if (s->buffers > 63) {
+ /* Each stream has a maximum of 63 buffers,
+ ensure we do not exceed that. */
+ s->buffers = 63;
+ s->buf_size = (max_size / s->buffers) & ~0xfff;
+ }
+ spin_lock_init(&s->qlock);
+ init_waitqueue_head(&s->waitq);
+ s->id = -1;
+ cx18_queue_init(&s->q_free);
+ cx18_queue_init(&s->q_full);
+ cx18_queue_init(&s->q_io);
+}
+
+static int cx18_prep_dev(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ u32 cap = cx->v4l2_cap;
+ int minor_offset = cx18_stream_info[type].minor_offset;
+ int minor;
+
+ /* These four fields are always initialized. If v4l2dev == NULL, then
+ this stream is not in use. In that case no other fields but these
+ four can be used. */
+ s->v4l2dev = NULL;
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+
+ /* Check whether the radio is supported */
+ if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO))
+ return 0;
+
+ /* Check whether VBI is supported */
+ if (type == CX18_ENC_STREAM_TYPE_VBI &&
+ !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
+ return 0;
+
+ /* card number + user defined offset + device offset */
+ minor = cx->num + cx18_first_minor + minor_offset;
+
+ /* User explicitly selected 0 buffers for these streams, so don't
+ create them. */
+ if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
+ cx->options.megabytes[type] == 0) {
+ CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
+ return 0;
+ }
+
+ cx18_stream_init(cx, type);
+
+ if (minor_offset == -1)
+ return 0;
+
+ /* allocate and initialize the v4l2 video device structure */
+ s->v4l2dev = video_device_alloc();
+ if (s->v4l2dev == NULL) {
+ CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
+ s->name);
+ return -ENOMEM;
+ }
+
+ s->v4l2dev->type =
+ VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
+ VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
+ snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
+ cx->num, s->name);
+
+ s->v4l2dev->minor = minor;
+ s->v4l2dev->dev = &cx->dev->dev;
+ s->v4l2dev->fops = cx18_stream_info[type].fops;
+ s->v4l2dev->release = video_device_release;
+
+ return 0;
+}
+
+/* Initialize v4l2 variables and register v4l2 devices */
+int cx18_streams_setup(struct cx18 *cx)
+{
+ int type;
+
+ /* Setup V4L2 Devices */
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ /* Prepare device */
+ if (cx18_prep_dev(cx, type))
+ break;
+
+ /* Allocate Stream */
+ if (cx18_stream_alloc(&cx->streams[type]))
+ break;
+ }
+ if (type == CX18_MAX_STREAMS)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ cx18_streams_cleanup(cx, 0);
+ return -ENOMEM;
+}
+
+static int cx18_reg_dev(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ int vfl_type = cx18_stream_info[type].vfl_type;
+ int minor;
+
+ /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
+ * We need a VFL_TYPE_TS defined.
+ */
+ if (strcmp("TS", s->name) == 0) {
+ /* just return if no DVB is supported */
+ if ((cx->card->hw_all & CX18_HW_DVB) == 0)
+ return 0;
+ if (cx18_dvb_register(s) < 0) {
+ CX18_ERR("DVB failed to register\n");
+ return -EINVAL;
+ }
+ }
+
+ if (s->v4l2dev == NULL)
+ return 0;
+
+ minor = s->v4l2dev->minor;
+
+ /* Register device. First try the desired minor, then any free one. */
+ if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+ video_register_device(s->v4l2dev, vfl_type, -1)) {
+ CX18_ERR("Couldn't register v4l2 device for %s minor %d\n",
+ s->name, minor);
+ video_device_release(s->v4l2dev);
+ s->v4l2dev = NULL;
+ return -ENOMEM;
+ }
+ minor = s->v4l2dev->minor;
+
+ switch (vfl_type) {
+ case VFL_TYPE_GRABBER:
+ CX18_INFO("Registered device video%d for %s (%d MB)\n",
+ minor, s->name, cx->options.megabytes[type]);
+ break;
+
+ case VFL_TYPE_RADIO:
+ CX18_INFO("Registered device radio%d for %s\n",
+ minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+ break;
+
+ case VFL_TYPE_VBI:
+ if (cx->options.megabytes[type])
+ CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
+ minor - MINOR_VFL_TYPE_VBI_MIN,
+ s->name, cx->options.megabytes[type]);
+ else
+ CX18_INFO("Registered device vbi%d for %s\n",
+ minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+ break;
+ }
+
+ return 0;
+}
+
+/* Register v4l2 devices */
+int cx18_streams_register(struct cx18 *cx)
+{
+ int type;
+ int err = 0;
+
+ /* Register V4L2 devices */
+ for (type = 0; type < CX18_MAX_STREAMS; type++)
+ err |= cx18_reg_dev(cx, type);
+
+ if (err == 0)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ cx18_streams_cleanup(cx, 1);
+ return -ENOMEM;
+}
+
+/* Unregister v4l2 devices */
+void cx18_streams_cleanup(struct cx18 *cx, int unregister)
+{
+ struct video_device *vdev;
+ int type;
+
+ /* Teardown all streams */
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ if (cx->streams[type].dvb.enabled)
+ cx18_dvb_unregister(&cx->streams[type]);
+
+ vdev = cx->streams[type].v4l2dev;
+
+ cx->streams[type].v4l2dev = NULL;
+ if (vdev == NULL)
+ continue;
+
+ cx18_stream_free(&cx->streams[type]);
+
+ /* Unregister or release device */
+ if (unregister)
+ video_unregister_device(vdev);
+ else
+ video_device_release(vdev);
+ }
+}
+
+static void cx18_vbi_setup(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ int raw = cx->vbi.sliced_in->service_set == 0;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int lines;
+
+ if (cx->is_60hz) {
+ cx->vbi.count = 12;
+ cx->vbi.start[0] = 10;
+ cx->vbi.start[1] = 273;
+ } else { /* PAL/SECAM */
+ cx->vbi.count = 18;
+ cx->vbi.start[0] = 6;
+ cx->vbi.start[1] = 318;
+ }
+
+ /* setup VBI registers */
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+
+ /* determine number of lines and total number of VBI bytes.
+ A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
+ The '- 1' byte is probably an unused U or V byte. Or something...
+ A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+ header, 42 data bytes + checksum (to be confirmed) */
+ if (raw) {
+ lines = cx->vbi.count * 2;
+ } else {
+ lines = cx->is_60hz ? 24 : 38;
+ if (cx->is_60hz)
+ lines += 2;
+ }
+
+ cx->vbi.enc_size = lines *
+ (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+
+ data[0] = s->handle;
+ /* Lines per field */
+ data[1] = (lines / 2) | ((lines / 2) << 16);
+ /* bytes per line */
+ data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+ /* Every X number of frames a VBI interrupt arrives
+ (frames as in 25 or 30 fps) */
+ data[3] = 1;
+ /* Setup VBI for the cx25840 digitizer */
+ if (raw) {
+ data[4] = 0x20602060;
+ data[5] = 0x30703070;
+ } else {
+ data[4] = 0xB0F0B0F0;
+ data[5] = 0xA0E0A0E0;
+ }
+
+ CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI)
+ cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+}
+
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+{
+ u32 data[MAX_MB_ARGUMENTS];
+ struct cx18 *cx = s->cx;
+ struct list_head *p;
+ int ts = 0;
+ int captype = 0;
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+ switch (s->type) {
+ case CX18_ENC_STREAM_TYPE_MPG:
+ captype = CAPTURE_CHANNEL_TYPE_MPEG;
+ cx->mpg_data_received = cx->vbi_data_inserted = 0;
+ cx->dualwatch_jiffies = jiffies;
+ cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
+ cx->search_pack_header = 0;
+ break;
+
+ case CX18_ENC_STREAM_TYPE_TS:
+ captype = CAPTURE_CHANNEL_TYPE_TS;
+ ts = 1;
+ break;
+ case CX18_ENC_STREAM_TYPE_YUV:
+ captype = CAPTURE_CHANNEL_TYPE_YUV;
+ break;
+ case CX18_ENC_STREAM_TYPE_PCM:
+ captype = CAPTURE_CHANNEL_TYPE_PCM;
+ break;
+ case CX18_ENC_STREAM_TYPE_VBI:
+ captype = cx->vbi.sliced_in->service_set ?
+ CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+ cx->vbi.frame = 0;
+ cx->vbi.inserted_frame = 0;
+ memset(cx->vbi.sliced_mpeg_size,
+ 0, sizeof(cx->vbi.sliced_mpeg_size));
+ break;
+ default:
+ return -EINVAL;
+ }
+ s->buffers_stolen = 0;
+
+ /* mute/unmute video */
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+ s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
+
+ /* Clear Streamoff flags in case left from last capture */
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE);
+ s->handle = data[0];
+ cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
+
+ if (atomic_read(&cx->capturing) == 0 && !ts) {
+ /* Stuff from Windows, we don't know what it is */
+ cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
+
+ cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
+ s->handle, cx->digitizer, cx->digitizer);
+
+ /* Setup VBI */
+ if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
+ cx18_vbi_setup(s);
+
+ /* assign program index info.
+ Mask 7: select I/P/B, Num_req: 400 max */
+ cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
+
+ /* Setup API for Stream */
+ cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
+ }
+
+ if (atomic_read(&cx->capturing) == 0) {
+ clear_bit(CX18_F_I_EOS, &cx->i_flags);
+ write_reg(7, CX18_DSP0_INTERRUPT_MASK);
+ }
+
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
+ (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
+ (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+
+ list_for_each(p, &s->q_free.list) {
+ struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
+
+ writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
+ writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1,
+ buf->id, s->buf_size);
+ }
+ /* begin_capture */
+ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
+ CX18_DEBUG_WARN("Error starting capture!\n");
+ cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ return -EINVAL;
+ }
+
+ /* you're live! sit back and await interrupts :) */
+ atomic_inc(&cx->capturing);
+ return 0;
+}
+
+void cx18_stop_all_captures(struct cx18 *cx)
+{
+ int i;
+
+ for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ continue;
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
+ cx18_stop_v4l2_encode_stream(s, 0);
+ }
+}
+
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
+{
+ struct cx18 *cx = s->cx;
+ unsigned long then;
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ /* This function assumes that you are allowed to stop the capture
+ and that we are actually capturing */
+
+ CX18_DEBUG_INFO("Stop Capture\n");
+
+ if (atomic_read(&cx->capturing) == 0)
+ return 0;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
+ else
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+
+ then = jiffies;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
+ CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
+ }
+
+ atomic_dec(&cx->capturing);
+
+ /* Clear capture and no-read bits */
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+
+ cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ s->handle = 0xffffffff;
+
+ if (atomic_read(&cx->capturing) > 0)
+ return 0;
+
+ write_reg(5, CX18_DSP0_INTERRUPT_MASK);
+ wake_up(&s->waitq);
+
+ return 0;
+}
+
+u32 cx18_find_handle(struct cx18 *cx)
+{
+ int i;
+
+ /* find first available handle to be used for global settings */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev && s->handle)
+ return s->handle;
+ }
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
new file mode 100644
index 000000000000..f327e947b24f
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -0,0 +1,33 @@
+/*
+ * cx18 init/start/stop/exit stream functions
+ *
+ * Derived from ivtv-streams.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+u32 cx18_find_handle(struct cx18 *cx);
+int cx18_streams_setup(struct cx18 *cx);
+int cx18_streams_register(struct cx18 *cx);
+void cx18_streams_cleanup(struct cx18 *cx, int unregister);
+
+/* Capture related */
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
+
+void cx18_stop_all_captures(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
new file mode 100644
index 000000000000..22e76ee3f447
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -0,0 +1,208 @@
+/*
+ * cx18 Vertical Blank Interval support functions
+ *
+ * Derived from ivtv-vbi.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-vbi.h"
+#include "cx18-ioctl.h"
+#include "cx18-queue.h"
+#include "cx18-av-core.h"
+
+static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+{
+ int line = 0;
+ int i;
+ u32 linemask[2] = { 0, 0 };
+ unsigned short size;
+ static const u8 mpeg_hdr_data[] = {
+ 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
+ 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
+ 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
+ 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+ };
+ const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
+ int idx = cx->vbi.frame % CX18_VBI_FRAMES;
+ u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0];
+
+ for (i = 0; i < lines; i++) {
+ struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i;
+ int f, l;
+
+ if (sdata->id == 0)
+ continue;
+
+ l = sdata->line - 6;
+ f = sdata->field;
+ if (f)
+ l += 18;
+ if (l < 32)
+ linemask[0] |= (1 << l);
+ else
+ linemask[1] |= (1 << (l - 32));
+ dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id);
+ memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42);
+ line++;
+ }
+ memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
+ if (line == 36) {
+ /* All lines are used, so there is no space for the linemask
+ (the max size of the VBI data is 36 * 43 + 4 bytes).
+ So in this case we use the magic number 'ITV0'. */
+ memcpy(dst + sd, "ITV0", 4);
+ memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+ size = 4 + ((43 * line + 3) & ~3);
+ } else {
+ memcpy(dst + sd, "cx0", 4);
+ memcpy(dst + sd + 4, &linemask[0], 8);
+ size = 12 + ((43 * line + 3) & ~3);
+ }
+ dst[4+16] = (size + 10) >> 8;
+ dst[5+16] = (size + 10) & 0xff;
+ dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
+ dst[10+16] = (pts_stamp >> 22) & 0xff;
+ dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
+ dst[12+16] = (pts_stamp >> 7) & 0xff;
+ dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
+ cx->vbi.sliced_mpeg_size[idx] = sd + size;
+}
+
+/* Compress raw VBI format, removes leading SAV codes and surplus space
+ after the field.
+ Returns new compressed size. */
+static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
+{
+ u32 line_size = cx->vbi.raw_decoder_line_size;
+ u32 lines = cx->vbi.count;
+ u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
+ u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
+ u8 *q = buf;
+ u8 *p;
+ int i;
+
+ for (i = 0; i < lines; i++) {
+ p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] ||
+ (p[3] != sav1 && p[3] != sav2))
+ break;
+ memcpy(q, p + 4, line_size - 4);
+ q += line_size - 4;
+ }
+ return lines * (line_size - 4);
+}
+
+
+/* Compressed VBI format, all found sliced blocks put next to one another
+ Returns new compressed size */
+static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
+ u32 size, u8 sav)
+{
+ u32 line_size = cx->vbi.sliced_decoder_line_size;
+ struct v4l2_decode_vbi_line vbi;
+ int i;
+
+ /* find the first valid line */
+ for (i = 0; i < size; i++, buf++) {
+ if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+ break;
+ }
+
+ size -= i;
+ if (size < line_size)
+ return line;
+ for (i = 0; i < size / line_size; i++) {
+ u8 *p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
+ continue;
+ vbi.p = p + 4;
+ cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+ if (vbi.type) {
+ cx->vbi.sliced_data[line].id = vbi.type;
+ cx->vbi.sliced_data[line].field = vbi.is_second_field;
+ cx->vbi.sliced_data[line].line = vbi.line;
+ memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42);
+ line++;
+ }
+ }
+ return line;
+}
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ u64 pts_stamp, int streamtype)
+{
+ u8 *p = (u8 *) buf->buf;
+ u32 size = buf->bytesused;
+ int lines;
+
+ if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
+ return;
+
+ /* Raw VBI data */
+ if (cx->vbi.sliced_in->service_set == 0) {
+ u8 type;
+
+ cx18_buf_swap(buf);
+
+ type = p[3];
+
+ size = buf->bytesused = compress_raw_buf(cx, p, size);
+
+ /* second field of the frame? */
+ if (type == cx->vbi.raw_decoder_sav_even_field) {
+ /* Dirty hack needed for backwards
+ compatibility of old VBI software. */
+ p += size - 4;
+ memcpy(p, &cx->vbi.frame, 4);
+ cx->vbi.frame++;
+ }
+ return;
+ }
+
+ /* Sliced VBI data with data insertion */
+ cx18_buf_swap(buf);
+
+ /* first field */
+ lines = compress_sliced_buf(cx, 0, p, size / 2,
+ cx->vbi.sliced_decoder_sav_odd_field);
+ /* second field */
+ /* experimentation shows that the second half does not always
+ begin at the exact address. So start a bit earlier
+ (hence 32). */
+ lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
+ size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
+ /* always return at least one empty line */
+ if (lines == 0) {
+ cx->vbi.sliced_data[0].id = 0;
+ cx->vbi.sliced_data[0].line = 0;
+ cx->vbi.sliced_data[0].field = 0;
+ lines = 1;
+ }
+ buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]);
+ memcpy(p, &cx->vbi.sliced_data[0], size);
+
+ if (cx->vbi.insert_mpeg)
+ copy_vbi_data(cx, lines, pts_stamp);
+ cx->vbi.frame++;
+}
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h
new file mode 100644
index 000000000000..c56ff7d28f20
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-vbi.h
@@ -0,0 +1,26 @@
+/*
+ * cx18 Vertical Blank Interval support functions
+ *
+ * Derived from ivtv-vbi.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ u64 pts_stamp, int streamtype);
+int cx18_used_line(struct cx18 *cx, int line, int field);
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
new file mode 100644
index 000000000000..d5c7a6f968dd
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -0,0 +1,34 @@
+/*
+ * cx18 driver version information
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 CX18_VERSION_H
+#define CX18_VERSION_H
+
+#define CX18_DRIVER_NAME "cx18"
+#define CX18_DRIVER_VERSION_MAJOR 1
+#define CX18_DRIVER_VERSION_MINOR 0
+#define CX18_DRIVER_VERSION_PATCHLEVEL 0
+
+#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
+#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
+ CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL)
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c
new file mode 100644
index 000000000000..2e5c41939330
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-video.c
@@ -0,0 +1,45 @@
+/*
+ * cx18 video interface functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cx18-driver.h"
+#include "cx18-video.h"
+#include "cx18-av-core.h"
+#include "cx18-cards.h"
+
+void cx18_video_set_io(struct cx18 *cx)
+{
+ struct v4l2_routing route;
+ int inp = cx->active_input;
+ u32 type;
+
+ route.input = cx->card->video_inputs[inp].video_input;
+ route.output = 0;
+ cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+ type = cx->card->video_inputs[inp].video_type;
+
+ if (type == CX18_CARD_INPUT_VID_TUNER)
+ route.input = 0; /* Tuner */
+ else if (type < CX18_CARD_INPUT_COMPOSITE1)
+ route.input = 2; /* S-Video */
+ else
+ route.input = 1; /* Composite */
+}
diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h
new file mode 100644
index 000000000000..529006a06e5c
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-video.h
@@ -0,0 +1,22 @@
+/*
+ * cx18 video interface functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+void cx18_video_set_io(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
new file mode 100644
index 000000000000..33f78da9dba8
--- /dev/null
+++ b/drivers/media/video/cx18/cx23418.h
@@ -0,0 +1,458 @@
+/*
+ * cx18 header containing common defines.
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 CX23418_H
+#define CX23418_H
+
+#include <media/cx2341x.h>
+
+#define MGR_CMD_MASK 0x40000000
+/* The MSB of the command code indicates that this is the completion of a
+ command */
+#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000)
+
+/* Description: This command creates a new instance of a certain task
+ IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is
+ the processor on which the task YYY will be created
+ OUT[0] - Task handle. This handle is passed along with commands to
+ dispatch to the right instance of the task
+ ReturnCode - One of the ERR_SYS_... */
+#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001)
+
+/* Description: This command destroys an instance of a task
+ IN[0] - Task handle. Hanlde of the task to destroy
+ ReturnCode - One of the ERR_SYS_... */
+#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002)
+
+/* All commands for CPU have the following mask set */
+#define CPU_CMD_MASK 0x20000000
+#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000)
+#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000)
+#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000)
+
+#define EPU_CMD_MASK 0x02000000
+#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000)
+#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000)
+
+/* Description: This command indicates that a Memory Descriptor List has been
+ filled with the requested channel type
+ IN[0] - Task handle. Handle of the task
+ IN[1] - Offset of the MDL_ACK from the beginning of the local DDR.
+ IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1]
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001)
+
+/* Something interesting happened
+ IN[0] - A value to log
+ IN[1] - An offset of a string in the MiniMe memory;
+ 0/zero/NULL means "I have nothing to say" */
+#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003)
+
+/* Description: This command starts streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to start
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002)
+
+/* Description: This command stops streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to stop
+ IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only)
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003)
+
+/* Description: This command pauses streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to pause
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007)
+
+/* Description: This command resumes streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to resume
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008)
+
+#define CAPTURE_CHANNEL_TYPE_NONE 0
+#define CAPTURE_CHANNEL_TYPE_MPEG 1
+#define CAPTURE_CHANNEL_TYPE_INDEX 2
+#define CAPTURE_CHANNEL_TYPE_YUV 3
+#define CAPTURE_CHANNEL_TYPE_PCM 4
+#define CAPTURE_CHANNEL_TYPE_VBI 5
+#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6
+#define CAPTURE_CHANNEL_TYPE_TS 7
+#define CAPTURE_CHANNEL_TYPE_MAX 15
+
+/* Description: This command sets the channel type. This can only be done
+ when stopped.
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Channel Type. See Below.
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1)
+
+/* Description: Set stream output type
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - type
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012)
+
+/* Description: Set video input resolution and frame rate
+ IN[0] - task handle
+ IN[1] - reserved
+ IN[2] - reserved
+ IN[3] - reserved
+ IN[4] - reserved
+ IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004)
+
+/* Description: Set video frame rate
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - video bit rate mode
+ IN[2] - video average rate
+ IN[3] - video peak rate
+ IN[4] - system mux rate
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005)
+
+/* Description: Set video output resolution
+ IN[0] - task handle
+ IN[1] - horizontal size
+ IN[2] - vertical size
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006)
+
+/* Description: This command set filter parameters
+ IN[0] - Task handle. Handle of the task
+ IN[1] - type, 0 - temporal, 1 - spatial, 2 - median
+ IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic
+ median: 0 = disable, 1 = horizontal, 2 = vertical,
+ 3 = horizontal/vertical, 4 = diagonal
+ IN[3] - strength, temporal 0 - 31, spatial 0 - 15
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009)
+
+/* Description: This command set spatial filter type
+ IN[0] - Task handle.
+ IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
+ 3 = 2D H/V separable, 4 = 2D symmetric non-separable
+ IN[2] - chroma type: 0 - diable, 1 = 1D horizontal
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C)
+
+/* Description: This command set coring levels for median filter
+ IN[0] - Task handle.
+ IN[1] - luma_high
+ IN[2] - luma_low
+ IN[3] - chroma_high
+ IN[4] - chroma_low
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E)
+
+/* Description: This command set the picture type mask for index file
+ IN[0] - 0 = disable index file output
+ 1 = output I picture
+ 2 = P picture
+ 4 = B picture
+ other = illegal */
+#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010)
+
+/* Description: Set audio parameters
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - audio parameter
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011)
+
+/* Description: Set video mute
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - bit31-24: muteYvalue
+ bit23-16: muteUvalue
+ bit15-8: muteVvalue
+ bit0: 1:mute, 0: unmute
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013)
+
+/* Description: Set audio mute
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - mute/unmute
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014)
+
+/* Description: Set stream output type
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - subType
+ SET_INITIAL_SCR 1
+ SET_QUALITY_MODE 2
+ SET_VIM_PROTECT_MODE 3
+ SET_PTS_CORRECTION 4
+ SET_USB_FLUSH_MODE 5
+ SET_MERAQPAR_ENABLE 6
+ SET_NAV_PACK_INSERTION 7
+ SET_SCENE_CHANGE_ENABLE 8
+ IN[2] - parameter 1
+ IN[3] - parameter 2
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015)
+
+/* Description: Set raw VBI parameters
+ IN[0] - Task handle
+ IN[1] - No. of input lines per field:
+ bit[15:0]: field 1,
+ bit[31:16]: field 2
+ IN[2] - No. of input bytes per line
+ IN[3] - No. of output frames per transfer
+ IN[4] - start code
+ IN[5] - stop code
+ ReturnCode */
+#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016)
+
+/* Description: Set capture line No.
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - height1
+ IN[2] - height2
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017)
+
+/* Description: Set copyright
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - copyright
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018)
+
+/* Description: Set audio PID
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - PID
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019)
+
+/* Description: Set video PID
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - PID
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A)
+
+/* Description: Set Vertical Crop Line
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - Line
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B)
+
+/* Description: Set COP structure
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - M
+ IN[2] - N
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C)
+
+/* Description: Set Scene Change Detection
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - scene change
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D)
+
+/* Description: Set Aspect Ratio
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - AspectRatio
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E)
+
+/* Description: Set Skip Input Frame
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - skip input frames
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F)
+
+/* Description: Set sliced VBI parameters -
+ Note This API will only apply to MPEG and Sliced VBI Channels
+ IN[0] - Task handle
+ IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext
+ IN[2] - start / stop line
+ bit[15:0] start line number
+ bit[31:16] stop line number
+ IN[3] - number of output frames per interrupt
+ IN[4] - VBI insertion mode
+ bit 0: output user data, 1 - enable
+ bit 1: output private stream, 1 - enable
+ bit 2: mux option, 0 - in GOP, 1 - in picture
+ bit[7:0] private stream ID
+ IN[5] - insertion period while mux option is in picture
+ ReturnCode - VBI data offset */
+#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020)
+
+/* Description: Set the user data place holder
+ IN[0] - type of data (0 for user)
+ IN[1] - Stuffing period
+ IN[2] - ID data size in word (less than 10)
+ IN[3] - Pointer to ID buffer */
+#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021)
+
+
+/* Description:
+ In[0] Task Handle
+ return parameter:
+ Out[0] Reserved
+ Out[1] Video PTS bit[32:2] of last output video frame.
+ Out[2] Video PTS bit[ 1:0] of last output video frame.
+ Out[3] Hardware Video PTS counter bit[31:0],
+ these bits get incremented on every 90kHz clock tick.
+ Out[4] Hardware Video PTS counter bit32,
+ these bits get incremented on every 90kHz clock tick.
+ ReturnCode */
+#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
+
+/* Below is the list of commands related to the data exchange */
+#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
+
+/* Description: This command provides the physical base address of the local
+ DDR as viewed by EPU
+ IN[0] - Physical offset where EPU has the local DDR mapped
+ ReturnCode - One of the ERR_DE_... */
+#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001)
+
+/* Description: This command provides the offsets in the device memory where
+ the 2 cx18_mdl_ack blocks reside
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Offset of the first cx18_mdl_ack from the beginning of the
+ local DDR.
+ IN[2] - Offset of the second cx18_mdl_ack from the beginning of the
+ local DDR.
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002)
+
+/* Description: This command provides the offset to a Memory Descriptor List
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Offset of the MDL from the beginning of the local DDR.
+ IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1]
+ IN[3] - Buffer ID
+ IN[4] - Total buffer length
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005)
+
+/* Description: This command requests return of all current Memory
+ Descriptor Lists to the driver
+ IN[0] - Task handle. Handle of the task to start
+ ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */
+
+/* Description: This command signals the cpu that the dat buffer has been
+ consumed and ready for re-use.
+ IN[0] - Task handle. Handle of the task
+ IN[1] - Offset of the data block from the beginning of the local DDR.
+ IN[2] - Number of bytes in the data block
+ ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */
+
+/* No Error / Success */
+#define CNXT_OK 0x000000
+
+/* Received unknown command */
+#define CXERR_UNK_CMD 0x000001
+
+/* First parameter in the command is invalid */
+#define CXERR_INVALID_PARAM1 0x000002
+
+/* Second parameter in the command is invalid */
+#define CXERR_INVALID_PARAM2 0x000003
+
+/* Device interface is not open/found */
+#define CXERR_DEV_NOT_FOUND 0x000004
+
+/* Requested function is not implemented/available */
+#define CXERR_NOTSUPPORTED 0x000005
+
+/* Invalid pointer is provided */
+#define CXERR_BADPTR 0x000006
+
+/* Unable to allocate memory */
+#define CXERR_NOMEM 0x000007
+
+/* Object/Link not found */
+#define CXERR_LINK 0x000008
+
+/* Device busy, command cannot be executed */
+#define CXERR_BUSY 0x000009
+
+/* File/device/handle is not open. */
+#define CXERR_NOT_OPEN 0x00000A
+
+/* Value is out of range */
+#define CXERR_OUTOFRANGE 0x00000B
+
+/* Buffer overflow */
+#define CXERR_OVERFLOW 0x00000C
+
+/* Version mismatch */
+#define CXERR_BADVER 0x00000D
+
+/* Operation timed out */
+#define CXERR_TIMEOUT 0x00000E
+
+/* Operation aborted */
+#define CXERR_ABORT 0x00000F
+
+/* Specified I2C device not found for read/write */
+#define CXERR_I2CDEV_NOTFOUND 0x000010
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_XFERERR 0x000011
+
+/* Chanel changing component not ready */
+#define CXERR_CHANNELNOTREADY 0x000012
+
+/* PPU (Presensation/Decoder) mail box is corrupted */
+#define CXERR_PPU_MB_CORRUPT 0x000013
+
+/* CPU (Capture/Encoder) mail box is corrupted */
+#define CXERR_CPU_MB_CORRUPT 0x000014
+
+/* APU (Audio) mail box is corrupted */
+#define CXERR_APU_MB_CORRUPT 0x000015
+
+/* Unable to open file for reading */
+#define CXERR_FILE_OPEN_READ 0x000016
+
+/* Unable to open file for writing */
+#define CXERR_FILE_OPEN_WRITE 0x000017
+
+/* Unable to find the I2C section specified */
+#define CXERR_I2C_BADSECTION 0x000018
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_DATALOW 0x000019
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_CLOCKLOW 0x00001A
+
+/* No Interrupt received from HW (for I2C access) */
+#define CXERR_NO_HW_I2C_INTR 0x00001B
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NOT_READY 0x00001C
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NO_ACK 0x00001D
+
+/* The are no buffers ready. Try again soon! */
+#define CXERR_NODATA_AGAIN 0x00001E
+
+/* The stream is stopping. Function not alllowed now! */
+#define CXERR_STOPPING_STATUS 0x00001F
+
+/* Trying to access hardware when the power is turned OFF */
+#define CXERR_DEVPOWER_OFF 0x000020
+
+#endif /* CX23418_H */
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index ca5fbce3a909..7bf14c9a15c7 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_CX23885
tristate "Conexant cx23885 (2388x successor) support"
depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT
+ depends on HOTPLUG # due to FW_LOADER
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
@@ -9,14 +10,15 @@ config VIDEO_CX23885
select VIDEO_IR
select VIDEOBUF_DVB
select VIDEO_CX25840
- select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
+ select VIDEO_CX2341X
+ select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
- select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
- select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
- select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Conexant 23885 based
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index d7b0721af062..29c23b44c13c 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -3,6 +3,7 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx2
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 6ebf58724a01..20e05f230546 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -200,6 +200,10 @@ struct cx23885_subid cx23885_subids[] = {
.card = CX23885_BOARD_HAUPPAUGE_HVR1200,
}, {
.subvendor = 0x0070,
+ .subdevice = 0x71d3,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
+ }, {
+ .subvendor = 0x0070,
.subdevice = 0x8101,
.card = CX23885_BOARD_HAUPPAUGE_HVR1700,
}, {
@@ -245,6 +249,33 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
/* Make sure we support the board model */
switch (tv.model)
{
+ case 71009:
+ /* WinTV-HVR1200 (PCIe, Retail, full height)
+ * DVB-T and basic analog */
+ case 71359:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71439:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71449:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71939:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71949:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71959:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71979:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71999:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
@@ -263,8 +294,11 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 80019:
/* WinTV-HVR1400 (Express Card, Retail, IR,
* DVB-T and Basic analog */
+ case 81509:
+ /* WinTV-HVR1700 (PCIe, OEM, No IR, half height)
+ * DVB-T and MPEG2 HW Encoder */
case 81519:
- /* WinTV-HVR1700 (PCIe, Retail, No IR, half height,
+ /* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
* DVB-T and MPEG2 HW Encoder */
break;
default:
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index f05649727b60..022aa391937a 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -37,7 +37,6 @@
#include "lgdt330x.h"
#include "xc5000.h"
#include "tda10048.h"
-#include "dvb-pll.h"
#include "tuner-xc2028.h"
#include "tuner-simple.h"
#include "dib7000p.h"
@@ -385,12 +384,10 @@ static int dvb_register(struct cx23885_tsport *port)
port->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500q_config,
&dev->i2c_bus[0].i2c_adap);
- if (port->dvb.frontend != NULL) {
- hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
+ if (port->dvb.frontend != NULL)
dvb_attach(xc5000_attach, port->dvb.frontend,
&i2c_bus->i2c_adap,
- &hauppauge_hvr1500q_tunerconfig);
- }
+ &hauppauge_hvr1500q_tunerconfig, i2c_bus);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
i2c_bus = &dev->i2c_bus[1];
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
index 7cf29a03ed63..448f4cd0ce34 100644
--- a/drivers/media/video/cx25840/Kconfig
+++ b/drivers/media/video/cx25840/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_CX25840
tristate "Conexant CX2584x audio/video decoders"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
---help---
Support for the Conexant CX2584x audio/video decoders.
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 7fde678b2c4a..607efdcd22f8 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1209,7 +1209,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
/* ----------------------------------------------------------------------- */
-static int cx25840_probe(struct i2c_client *client)
+static int cx25840_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct cx25840_state *state;
u32 id;
@@ -1283,10 +1284,17 @@ static int cx25840_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id cx25840_id[] = {
+ { "cx25840", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cx25840_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cx25840",
.driverid = I2C_DRIVERID_CX25840,
.command = cx25840_command,
.probe = cx25840_probe,
.remove = cx25840_remove,
+ .id_table = cx25840_id,
};
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 27635cdcbaf2..10e20d8196dc 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -2,7 +2,6 @@ config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
depends on VIDEO_DEV && PCI && I2C && INPUT
select I2C_ALGOBIT
- select FW_LOADER
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
select VIDEO_TUNER
@@ -34,8 +33,9 @@ config VIDEO_CX88_ALSA
config VIDEO_CX88_BLACKBIRD
tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
- depends on VIDEO_CX88
+ depends on VIDEO_CX88 && HOTPLUG
select VIDEO_CX2341X
+ select FW_LOADER
---help---
This adds support for MPEG encoder cards based on the
Blackbird reference design, using the Conexant 2388x
@@ -57,7 +57,7 @@ config VIDEO_CX88_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 532cee35eb3c..6ec30f242578 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 2b6b283cda15..aeba26dc0a37 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -57,6 +57,9 @@ MODULE_PARM_DESC(latency,"pci latency timer");
/* ------------------------------------------------------------------ */
/* board config info */
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
@@ -2446,25 +2449,31 @@ EXPORT_SYMBOL_GPL(cx88_setup_xc3028);
static void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
if (0 == core->i2c_rc) {
core->i2c_client.addr = 0xa0 >> 1;
- tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
+ tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom));
}
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_ROSLYN:
if (0 == core->i2c_rc)
- hauppauge_eeprom(core,eeprom+8);
+ hauppauge_eeprom(core, eeprom+8);
break;
case CX88_BOARD_GDI:
if (0 == core->i2c_rc)
- gdi_eeprom(core,eeprom);
+ gdi_eeprom(core, eeprom);
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
if (0 == core->i2c_rc)
- leadtek_eeprom(core,eeprom);
+ leadtek_eeprom(core, eeprom);
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
@@ -2474,7 +2483,7 @@ static void cx88_card_setup(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR1300:
if (0 == core->i2c_rc)
- hauppauge_eeprom(core,eeprom);
+ hauppauge_eeprom(core, eeprom);
break;
case CX88_BOARD_KWORLD_DVBS_100:
cx_write(MO_GP0_IO, 0x000007f8);
@@ -2555,6 +2564,35 @@ static void cx88_card_setup(struct cx88_core *core)
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
}
+ } /*end switch() */
+
+
+ /* Setup tuners */
+ if ((core->board.radio_type != UNSET)) {
+ tun_setup.mode_mask = T_RADIO;
+ tun_setup.type = core->board.radio_type;
+ tun_setup.addr = core->board.radio_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+ cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if (core->board.tuner_type != TUNER_ABSENT) {
+ tun_setup.mode_mask = mode_mask;
+ tun_setup.type = core->board.tuner_type;
+ tun_setup.addr = core->board.tuner_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+
+ cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ if (core->board.tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &core->board.tda9887_conf;
+
+ cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
}
if (core->board.tuner_type == TUNER_XC2028) {
@@ -2572,6 +2610,7 @@ static void cx88_card_setup(struct cx88_core *core)
ctl.fname);
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
}
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
}
/* ------------------------------------------------------------------ */
@@ -2710,7 +2749,6 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
if (TUNER_ABSENT != core->board.tuner_type)
request_module("tuner");
- cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
cx88_card_setup(core);
cx88_ir_init(core, pci);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 1c7fe6862a60..d96173ff1dba 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -509,9 +509,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->core->name);
- dvb_frontend_detach(dev->dvb.frontend);
- dvb_unregister_frontend(dev->dvb.frontend);
- dev->dvb.frontend = NULL;
return -EINVAL;
}
@@ -523,20 +520,23 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
static int dvb_register(struct cx8802_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
/* init struct videobuf_dvb */
- dev->dvb.name = dev->core->name;
+ dev->dvb.name = core->name;
dev->ts_gen_cntrl = 0x0c;
/* init frontend */
- switch (dev->core->boardnr) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_DTT759X);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, &core->i2c_adap,
+ DVB_PLL_THOMSON_DTT759X))
+ goto frontend_detach;
}
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -545,11 +545,12 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x60, &core->i2c_adap,
+ DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -559,29 +560,32 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_HVR3000:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216ME_MK3);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -589,28 +593,31 @@ static int dvb_register(struct cx8802_dev *dev)
* compatible, with a slightly different MT352 AGC gain. */
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_dual,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_LG_Z201);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_LG_Z201))
+ goto frontend_detach;
}
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -618,10 +625,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_ADSTECH_DVB_T_PCI:
dev->dvb.frontend = dvb_attach(mt352_attach,
&dntv_live_dvbt_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_UNKNOWN_1);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_UNKNOWN_1))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
@@ -630,32 +638,35 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&dev->vp3054->adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216ME_MK3);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
}
#else
- printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
+ printk(KERN_ERR "%s/2: built without vp3054 support\n",
+ core->name);
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_hybrid,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_THOMSON_FE6600);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_FE6600))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend == NULL)
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_mt352_xc3028,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
/*
* On this board, the demod provides the I2C bus pullup.
* We must not permit gate_ctrl to be performed, or
@@ -668,19 +679,18 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_THOMSON_DTT761X);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 1);
@@ -690,139 +700,137 @@ static int dvb_register(struct cx8802_dev *dev)
fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_MICROTUNE_4042FI5);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_MICROTUNE_4042FI5))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 9);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_THOMSON_DTT761X);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_gold,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
- dvb_attach(tda9887_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x43);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF))
+ goto frontend_detach;
+ if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x43))
+ goto frontend_detach;
}
break;
case CX88_BOARD_PCHDTV_HD5500:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&pchdtv_hd5500,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
- dvb_attach(tda9887_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x43);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF))
+ goto frontend_detach;
+ if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x43))
+ goto frontend_detach;
}
break;
case CX88_BOARD_ATI_HDTVWONDER:
dev->dvb.frontend = dvb_attach(nxt200x_attach,
&ati_hdtvwonder,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_PHILIPS_TUV1236D);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_TUV1236D))
+ goto frontend_detach;
}
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = dvb_attach(cx24123_attach,
&hauppauge_novas_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend) {
- dvb_attach(isl6421_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x08, 0x00, 0x00);
+ if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x08, 0x00, 0x00))
+ goto frontend_detach;
}
break;
case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = dvb_attach(cx24123_attach,
&kworld_dvbs_100_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend) {
- dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
}
break;
case CX88_BOARD_GENIATECH_DVBS:
dev->dvb.frontend = dvb_attach(cx24123_attach,
&geniatech_dvbs_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend) {
- dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
}
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
&pinnacle_pctv_hd_800i_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
/* tuner_config.video_dev must point to
* i2c_adap.algo_data
*/
- pinnacle_pctv_hd_800i_tuner_config.priv =
- dev->core->i2c_adap.algo_data;
- dvb_attach(xc5000_attach, dev->dvb.frontend,
- &dev->core->i2c_adap,
- &pinnacle_pctv_hd_800i_tuner_config);
+ if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+ &core->i2c_adap,
+ &pinnacle_pctv_hd_800i_tuner_config,
+ core->i2c_adap.algo_data))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
&dvico_hdtv5_pci_nano_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
- .i2c_adap = &dev->core->i2c_adap,
+ .i2c_adap = &core->i2c_adap,
.i2c_addr = 0x61,
.callback = cx88_pci_nano_callback,
};
@@ -841,50 +849,50 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
dev->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_geniatech_x8000_mt,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
break;
case CX88_BOARD_GENIATECH_X8000_MT:
dev->ts_gen_cntrl = 0x00;
dev->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_geniatech_x8000_mt,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
break;
case CX88_BOARD_KWORLD_ATSC_120:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
&kworld_atsc_120_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
dev->dvb.frontend = dvb_attach(s5h1411_attach,
&dvico_fusionhdtv7_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
/* tuner_config.video_dev must point to
* i2c_adap.algo_data
*/
- dvico_fusionhdtv7_tuner_config.priv =
- dev->core->i2c_adap.algo_data;
- dvb_attach(xc5000_attach, dev->dvb.frontend,
- &dev->core->i2c_adap,
- &dvico_fusionhdtv7_tuner_config);
+ if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+ &core->i2c_adap,
+ &dvico_fusionhdtv7_tuner_config,
+ core->i2c_adap.algo_data))
+ goto frontend_detach;
}
break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
- dev->core->name);
+ core->name);
break;
}
if (NULL == dev->dvb.frontend) {
printk(KERN_ERR
"%s/2: frontend initialization failed\n",
- dev->core->name);
+ core->name);
return -EINVAL;
}
@@ -892,11 +900,18 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
/* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+ cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
/* register everything */
return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr);
+
+frontend_detach:
+ if (dev->dvb.frontend) {
+ dvb_frontend_detach(dev->dvb.frontend);
+ dev->dvb.frontend = NULL;
+ }
+ return -EINVAL;
}
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index c6b44732a082..cb6a096069c7 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -99,42 +99,11 @@ static int cx8800_bit_getsda(void *data)
static int attach_inform(struct i2c_client *client)
{
- struct tuner_setup tun_setup;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->driver.name, client->addr, client->name);
- if (!client->driver->command)
- return 0;
-
- if (core->board.radio_type != UNSET) {
- if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
- tun_setup.mode_mask = T_RADIO;
- tun_setup.type = core->board.radio_type;
- tun_setup.addr = core->board.radio_addr;
- tun_setup.tuner_callback = cx88_tuner_callback;
- client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
- if (core->board.tuner_type != UNSET) {
- if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
-
- tun_setup.mode_mask = T_ANALOG_TV;
- tun_setup.type = core->board.tuner_type;
- tun_setup.addr = core->board.tuner_addr;
- tun_setup.tuner_callback = cx88_tuner_callback;
- client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
-
- if (core->board.tda9887_conf) {
- struct v4l2_priv_tun_config tda9887_cfg;
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &core->board.tda9887_conf;
-
- client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
- }
return 0;
}
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 9caffed2b6b8..16a5af30e9d1 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -35,7 +35,6 @@ config VIDEO_EM28XX_DVB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select VIDEOBUF_DVB
- select FW_LOADER
---help---
This adds support for DVB cards based on the
Empiatech em28xx chips.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 3d1c3cc337fe..8137a8c94bfc 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 50ccf3771204..3e4f3c7e92e7 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -420,7 +420,13 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
{ USB_DEVICE(0x2040, 0x6502),
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
- { USB_DEVICE(0x2040, 0x6513),
+ { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
{ USB_DEVICE(0x0ccd, 0x0042),
.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 7df81575b7f2..8cf4983f0039 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -251,7 +251,6 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->name);
dvb_frontend_detach(dev->dvb->frontend);
- dvb_unregister_frontend(dev->dvb->frontend);
dev->dvb->frontend = NULL;
return -EINVAL;
}
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 5e749c528a62..15d037ae25c5 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index b6171702c4d0..5d7ee8fcdd50 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,8 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+ depends on INPUT # due to VIDEO_IR
+ depends on HOTPLUG # due to FW_LOADER
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_IR
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index a0389014fa88..26ce0d6eaee1 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index e908649ea37c..4fb8faefe2ce 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -40,6 +40,8 @@
#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM)
+
/* usual i2c tuner addresses to probe */
static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
.radio = { I2C_CLIENT_END },
@@ -298,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
/* The PAL tuner is confirmed */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg600,
@@ -339,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
.lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 },
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg160,
@@ -375,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_pg600,
@@ -416,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
on the country/region setting of the user to decide which tuner
is available. */
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
.tuner = TUNER_PHILIPS_FM1236_MK3 },
{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
@@ -490,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020 },
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_tg5000tv,
.i2c = &ivtv_i2c_std,
@@ -521,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
},
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_va2000,
.i2c = &ivtv_i2c_std,
@@ -565,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_cx23416gyc,
@@ -597,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -627,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -667,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx,
.i2c = &ivtv_i2c_std,
@@ -704,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx2e,
.i2c = &ivtv_i2c_std,
@@ -739,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
.tuners = {
/* This card has a Philips FQ1216ME MK3 tuner */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd,
.i2c = &ivtv_i2c_std,
@@ -778,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Philips FQ1216ME MK5 tuner */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd2,
.i2c = &ivtv_i2c_std,
@@ -856,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020},
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_dctmvtvp1,
.i2c = &ivtv_i2c_std,
@@ -875,6 +877,7 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
static const struct ivtv_card ivtv_card_pg600v2 = {
.type = IVTV_CARD_PG600V2,
.name = "Yuan PG600-2, GotView PCI DVD Lite",
+ .comment = "only Composite and S-Video inputs are supported, not the tuner\n",
.v4l2_capabilities = IVTV_CAP_ENCODER,
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
@@ -921,6 +924,7 @@ static const struct ivtv_card ivtv_card_club3d = {
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
+ .xceive_pin = 12,
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -944,15 +948,22 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
.hw_audio_ctrl = IVTV_HW_CX25840,
- .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
.video_inputs = {
- { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
- { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
},
.audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
},
- .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+ /* enable line-in */
+ .gpio_init = { .direction = 0xe400, .initial_value = 0x4400 },
+ .xceive_pin = 10,
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
.pci_list = ivtv_pci_avertv_mce116,
.i2c = &ivtv_i2c_std,
};
@@ -990,7 +1001,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Partsnic PTI-5NF05 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
},
.pci_list = ivtv_pci_aver_pvr150,
.i2c = &ivtv_i2c_radio,
@@ -1058,12 +1069,48 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = {
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_asus_falcon2,
.i2c = &ivtv_i2c_std,
};
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia M104 miniPCI card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_m104 = {
+ .type = IVTV_CARD_AVER_M104,
+ .name = "AVerMedia M104",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
+ },
+ .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+ /* enable line-in + reset tuner */
+ .gpio_init = { .direction = 0xe400, .initial_value = 0x4000 },
+ .xceive_pin = 10,
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .pci_list = ivtv_pci_aver_m104,
+ .i2c = &ivtv_i2c_std,
+};
+
static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_pvr250,
&ivtv_card_pvr350,
@@ -1089,6 +1136,7 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_asus_falcon2,
&ivtv_card_aver_pvr150,
&ivtv_card_aver_ezmaker,
+ &ivtv_card_aver_m104,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
@@ -1120,7 +1168,8 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
if (index >= itv->nof_inputs)
return -EINVAL;
input->index = index;
- strcpy(input->name, input_strs[card_input->video_type - 1]);
+ strlcpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ?
V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
input->audioset = (1 << itv->nof_audio_inputs) - 1;
@@ -1137,7 +1186,7 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
if (index >= itv->card->nof_outputs)
return -EINVAL;
output->index = index;
- strcpy(output->name, card_output->name);
+ strlcpy(output->name, card_output->name, sizeof(output->name));
output->type = V4L2_OUTPUT_TYPE_ANALOG;
output->audioset = 1;
output->std = V4L2_STD_ALL;
@@ -1156,7 +1205,8 @@ int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio)
memset(audio, 0, sizeof(*audio));
if (index >= itv->nof_audio_inputs)
return -EINVAL;
- strcpy(audio->name, input_strs[aud_input->audio_type - 1]);
+ strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
audio->index = index;
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1167,6 +1217,6 @@ int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud
memset(aud_output, 0, sizeof(*aud_output));
if (itv->card->video_outputs == NULL || index != 0)
return -EINVAL;
- strcpy(aud_output->name, "A/V Audio Out");
+ strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name));
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 9186fa2ee5fc..748485dcebbd 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -48,7 +48,8 @@
#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */
#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */
#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */
-#define IVTV_CARD_LAST 23
+#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */
+#define IVTV_CARD_LAST 24
/* Variants of existing cards but with the same PCI IDs. The driver
detects these based on other device information.
@@ -244,6 +245,7 @@ struct ivtv_card_tuner_i2c {
struct ivtv_card {
int type;
char *name;
+ char *comment;
u32 v4l2_capabilities;
u32 hw_video; /* hardware used to process video */
u32 hw_audio; /* hardware used to process audio */
@@ -256,6 +258,7 @@ struct ivtv_card {
int nof_outputs;
const struct ivtv_card_output *video_outputs;
u8 gr_config; /* config byte for the ghost reduction device */
+ u8 xceive_pin; /* XCeive tuner GPIO reset pin */
/* GPIO card-specific settings */
struct ivtv_gpio_init gpio_init;
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index 8c02fa661591..c7e449f6397b 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -181,12 +181,12 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm
return 0;
}
/* Need sliced data for mpeg insertion */
- if (get_service_set(itv->vbi.sliced_in) == 0) {
+ if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) {
if (itv->is_60hz)
itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
else
itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
- expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
+ ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
}
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 065df53f80fd..797e636771da 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -190,6 +190,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t22 = ASUS Falcon2\n"
"\t\t\t23 = AverMedia PVR-150 Plus\n"
"\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
+ "\t\t\t25 = AverMedia M104 (not yet working)\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -852,6 +853,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
return 0;
}
+#ifdef MODULE
static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
const char *name, u32 id)
{
@@ -864,14 +866,16 @@ static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
IVTV_DEBUG_INFO("Loaded module %s\n", name);
return hw;
}
+#endif
static void ivtv_load_and_init_modules(struct ivtv *itv)
{
u32 hw = itv->card->hw_all;
unsigned i;
+#ifdef MODULE
/* load modules */
-#ifndef CONFIG_VIDEO_TUNER
+#ifndef CONFIG_MEDIA_TUNER
hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
#endif
#ifndef CONFIG_VIDEO_CX25840
@@ -910,6 +914,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
#ifndef CONFIG_VIDEO_M52790
hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
#endif
+#endif
/* check which i2c devices are actually found */
for (i = 0; i < 32; i++) {
@@ -1048,7 +1053,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_ENCODER_SIZE);
if (!itv->enc_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1060,7 +1065,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_DECODER_SIZE);
if (!itv->dec_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1076,7 +1081,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (!itv->reg_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_io;
}
@@ -1097,6 +1102,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
The PCI IDs are not always reliable. */
ivtv_process_eeprom(itv);
}
+ if (itv->card->comment)
+ IVTV_INFO("%s", itv->card->comment);
+ if (itv->card->v4l2_capabilities == 0) {
+ /* card was detected but is not supported */
+ retval = -ENODEV;
+ goto free_i2c;
+ }
if (itv->std == 0) {
itv->std = V4L2_STD_NTSC_M;
@@ -1195,13 +1207,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
}
- retval = ivtv_streams_setup(itv);
- if (retval) {
- IVTV_ERR("Error %d setting up streams\n", retval);
- goto free_i2c;
- }
-
- IVTV_DEBUG_IRQ("Masking interrupts\n");
/* clear interrupt mask, effectively disabling interrupts */
ivtv_set_irq_mask(itv, 0xffffffff);
@@ -1210,32 +1215,38 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
if (retval) {
IVTV_ERR("Failed to register irq %d\n", retval);
- goto free_streams;
+ goto free_i2c;
+ }
+
+ retval = ivtv_streams_setup(itv);
+ if (retval) {
+ IVTV_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
}
retval = ivtv_streams_register(itv);
if (retval) {
IVTV_ERR("Error %d registering devices\n", retval);
- goto free_irq;
+ goto free_streams;
}
IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
return 0;
- free_irq:
+free_streams:
+ ivtv_streams_cleanup(itv, 1);
+free_irq:
free_irq(itv->dev->irq, (void *)itv);
- free_streams:
- ivtv_streams_cleanup(itv);
- free_i2c:
+free_i2c:
exit_ivtv_i2c(itv);
- free_io:
+free_io:
ivtv_iounmap(itv);
- free_mem:
+free_mem:
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
- free_workqueue:
+free_workqueue:
destroy_workqueue(itv->irq_work_queues);
- err:
+err:
if (retval == 0)
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
@@ -1366,7 +1377,7 @@ static void ivtv_remove(struct pci_dev *pci_dev)
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
- ivtv_streams_cleanup(itv);
+ ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
exit_ivtv_i2c(itv);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index a7640c49f1d8..f2fa434b677b 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -755,8 +755,10 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
IVTV_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (eof || s->q_full.length || s->q_io.length)
+ if (s->q_full.length || s->q_io.length)
return POLLIN | POLLRDNORM;
+ if (eof)
+ return POLLHUP;
return 0;
}
@@ -985,6 +987,8 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
/* Find which card this open was on */
spin_lock(&ivtv_cards_lock);
for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+ if (ivtv_cards[x] == NULL)
+ continue;
/* find out which stream this open was on */
for (y = 0; y < IVTV_MAX_STREAMS; y++) {
s = &ivtv_cards[x]->streams[y];
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 688cd3856685..d8ac09f3cce6 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -128,20 +128,17 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
{
struct i2c_algo_bit_data *algo = dev;
struct ivtv *itv = algo->data;
- int curdir, curout;
+ u32 curout;
if (cmd != XC2028_TUNER_RESET)
return 0;
IVTV_DEBUG_INFO("Resetting tuner\n");
curout = read_reg(IVTV_REG_GPIO_OUT);
- curdir = read_reg(IVTV_REG_GPIO_DIR);
- curdir |= (1 << 12); /* GPIO bit 12 */
-
- curout &= ~(1 << 12);
+ curout &= ~(1 << itv->card->xceive_pin);
write_reg(curout, IVTV_REG_GPIO_OUT);
schedule_timeout_interruptible(msecs_to_jiffies(1));
- curout |= (1 << 12);
+ curout |= 1 << itv->card->xceive_pin;
write_reg(curout, IVTV_REG_GPIO_OUT);
schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 9824eafee021..32129f3ea836 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -136,7 +136,7 @@ static const u8 hw_addrs[] = {
};
/* This array should match the IVTV_HW_ defines */
-static const char * const hw_drivernames[] = {
+static const char * const hw_devicenames[] = {
"cx25840",
"saa7115",
"saa7127",
@@ -145,7 +145,7 @@ static const char * const hw_drivernames[] = {
"wm8775",
"cs53l32a",
"tveeprom",
- "saa7115",
+ "saa7114",
"upd64031a",
"upd64083",
"saa717x",
@@ -167,7 +167,7 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
return -1;
id = hw_driverids[idx];
memset(&info, 0, sizeof(info));
- strcpy(info.driver_name, hw_drivernames[idx]);
+ strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
info.addr = hw_addrs[idx];
for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
@@ -656,7 +656,7 @@ static const char *ivtv_i2c_id_name(u32 id)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (hw_driverids[i] == id)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -667,7 +667,7 @@ static const char *ivtv_i2c_hw_name(u32 hw)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (1 << i == hw)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -769,7 +769,7 @@ int init_ivtv_i2c(struct ivtv *itv)
* same size and GPIO must be the last entry.
*/
if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
- ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
+ ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
IVTV_ERR("Mismatched I2C hardware arrays\n");
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 15cac1812122..26cc0f6699fd 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -38,7 +38,7 @@
#include <linux/dvb/audio.h>
#include <linux/i2c-id.h>
-u16 service2vbi(int type)
+u16 ivtv_service2vbi(int type)
{
switch (type) {
case V4L2_SLICED_TELETEXT_B:
@@ -88,7 +88,7 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
return 0;
}
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
u16 set = fmt->service_set;
int f, l;
@@ -115,7 +115,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
return set != 0;
}
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{
int f, l;
u16 set = 0;
@@ -243,20 +243,31 @@ static int ivtv_validate_speed(int cur_speed, int new_speed)
int fact = new_speed < 0 ? -1 : 1;
int s;
- if (new_speed < 0) new_speed = -new_speed;
- if (cur_speed < 0) cur_speed = -cur_speed;
+ if (cur_speed == 0)
+ cur_speed = 1000;
+ if (new_speed < 0)
+ new_speed = -new_speed;
+ if (cur_speed < 0)
+ cur_speed = -cur_speed;
if (cur_speed <= new_speed) {
- if (new_speed > 1500) return fact * 2000;
- if (new_speed > 1000) return fact * 1500;
+ if (new_speed > 1500)
+ return fact * 2000;
+ if (new_speed > 1000)
+ return fact * 1500;
}
else {
- if (new_speed >= 2000) return fact * 2000;
- if (new_speed >= 1500) return fact * 1500;
- if (new_speed >= 1000) return fact * 1000;
- }
- if (new_speed == 0) return 1000;
- if (new_speed == 1 || new_speed == 1000) return fact * new_speed;
+ if (new_speed >= 2000)
+ return fact * 2000;
+ if (new_speed >= 1500)
+ return fact * 1500;
+ if (new_speed >= 1000)
+ return fact * 1000;
+ }
+ if (new_speed == 0)
+ return 1000;
+ if (new_speed == 1 || new_speed == 1000)
+ return fact * new_speed;
s = new_speed;
new_speed = 1000 / new_speed;
@@ -455,7 +466,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
}
- vbifmt->service_set = get_service_set(vbifmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
break;
}
@@ -470,12 +481,12 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
V4L2_SLICED_VBI_525;
- expand_service_set(vbifmt, itv->is_50hz);
+ ivtv_expand_service_set(vbifmt, itv->is_50hz);
break;
}
itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
- vbifmt->service_set = get_service_set(vbifmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
break;
}
case V4L2_BUF_TYPE_VBI_OUTPUT:
@@ -629,9 +640,9 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
if (vbifmt->service_set)
- expand_service_set(vbifmt, itv->is_50hz);
+ ivtv_expand_service_set(vbifmt, itv->is_50hz);
set = check_service_set(vbifmt, itv->is_50hz);
- vbifmt->service_set = get_service_set(vbifmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
if (!set_fmt)
return 0;
@@ -741,10 +752,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
struct v4l2_capability *vcap = arg;
memset(vcap, 0, sizeof(*vcap));
- strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */
- strncpy(vcap->card, itv->card_name,
- sizeof(vcap->card)-1); /* card type */
- strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
+ strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
@@ -1018,7 +1028,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_std_60hz : ivtv_std_50hz;
vs->index = idx;
vs->id = enum_stds[idx].std;
- strcpy(vs->name, enum_stds[idx].name);
+ strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
break;
}
@@ -1102,10 +1112,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
- strcpy(vt->name, "ivtv Radio Tuner");
+ strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_RADIO;
} else {
- strcpy(vt->name, "ivtv TV Tuner");
+ strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_ANALOG_TV;
}
break;
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index a03351b6853d..4e67f0ed1fc0 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -21,9 +21,9 @@
#ifndef IVTV_IOCTL_H
#define IVTV_IOCTL_H
-u16 service2vbi(int type);
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
+u16 ivtv_service2vbi(int type);
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index a329c4689dbf..d8ba3a4a8761 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -384,7 +384,7 @@ static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
add_timer(&itv->dma_timer);
}
@@ -400,7 +400,7 @@ static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
add_timer(&itv->dma_timer);
}
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index 3e1deec67a5e..fc8b1eaa333b 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -203,14 +203,14 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
s->dma != PCI_DMA_NONE ? "DMA " : "",
s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
- s->sg_pending = kzalloc(SGsize, GFP_KERNEL);
+ s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
if (s->sg_pending == NULL) {
IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
return -ENOMEM;
}
s->sg_pending_size = 0;
- s->sg_processing = kzalloc(SGsize, GFP_KERNEL);
+ s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
if (s->sg_processing == NULL) {
IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
kfree(s->sg_pending);
@@ -219,7 +219,8 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
}
s->sg_processing_size = 0;
- s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
+ s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element),
+ GFP_KERNEL|__GFP_NOWARN);
if (s->sg_dma == NULL) {
IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
kfree(s->sg_pending);
@@ -235,11 +236,12 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
/* allocate stream buffers. Initially all buffers are in q_free. */
for (i = 0; i < s->buffers; i++) {
- struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
+ struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer),
+ GFP_KERNEL|__GFP_NOWARN);
if (buf == NULL)
break;
- buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
+ buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN);
if (buf->buf == NULL) {
kfree(buf);
break;
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 4ab8d36831ba..c47c2b945147 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -244,7 +244,7 @@ int ivtv_streams_setup(struct ivtv *itv)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv);
+ ivtv_streams_cleanup(itv, 0);
return -ENOMEM;
}
@@ -304,12 +304,12 @@ int ivtv_streams_register(struct ivtv *itv)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv);
+ ivtv_streams_cleanup(itv, 1);
return -ENOMEM;
}
/* Unregister v4l2 devices */
-void ivtv_streams_cleanup(struct ivtv *itv)
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
{
int type;
@@ -322,8 +322,11 @@ void ivtv_streams_cleanup(struct ivtv *itv)
continue;
ivtv_stream_free(&itv->streams[type]);
- /* Unregister device */
- video_unregister_device(vdev);
+ /* Unregister or release device */
+ if (unregister)
+ video_unregister_device(vdev);
+ else
+ video_device_release(vdev);
}
}
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
index 3d76a415fbd8..a653a5136417 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -23,7 +23,7 @@
int ivtv_streams_setup(struct ivtv *itv);
int ivtv_streams_register(struct ivtv *itv);
-void ivtv_streams_cleanup(struct ivtv *itv);
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister);
/* Capture related */
int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s);
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index c151bcf5519a..71798f0da27f 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -169,7 +169,8 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
linemask[0] |= (1 << l);
else
linemask[1] |= (1 << (l - 32));
- dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id);
+ dst[sd + 12 + line * 43] =
+ ivtv_service2vbi(itv->vbi.sliced_data[i].id);
memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
line++;
}
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 0f1d4cc4b4d9..02c5ab071d1b 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -23,7 +23,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
#define IVTV_DRIVER_VERSION_MINOR 2
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 62f70bd5e3cb..a9417f6e4087 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -908,7 +908,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
}
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
- yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
+ yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
if (yi->blanking_ptr) {
yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
} else {
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 3b23fc05f7c4..73be154f7f05 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -532,7 +532,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "cx23415 TV out");
+ strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
fix->smem_start = oi->video_pbase;
fix->smem_len = oi->video_buffer_size;
fix->type = FB_TYPE_PACKED_PIXELS;
@@ -948,7 +948,8 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
}
/* Allocate the pseudo palette */
- oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ oi->ivtvfb_info.pseudo_palette =
+ kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
if (!oi->ivtvfb_info.pseudo_palette) {
IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
@@ -1056,7 +1057,8 @@ static int ivtvfb_init_card(struct ivtv *itv)
return -EBUSY;
}
- itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+ itv->osd_info = kzalloc(sizeof(struct osd_info),
+ GFP_ATOMIC|__GFP_NOWARN);
if (itv->osd_info == NULL) {
IVTVFB_ERR("Failed to allocate memory for osd_info\n");
return -ENOMEM;
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index d4bf14c284ef..8e0160d275ca 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -126,7 +126,8 @@ static int m52790_command(struct i2c_client *client, unsigned int cmd,
/* i2c implementation */
-static int m52790_probe(struct i2c_client *client)
+static int m52790_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct m52790_state *state;
@@ -134,8 +135,6 @@ static int m52790_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- snprintf(client->name, sizeof(client->name) - 1, "m52790");
-
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -158,11 +157,18 @@ static int m52790_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id m52790_id[] = {
+ { "m52790", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, m52790_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "m52790",
.driverid = I2C_DRIVERID_M52790,
.command = m52790_command,
.probe = m52790_probe,
.remove = m52790_remove,
+ .id_table = m52790_id,
};
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index b73c740f7fb2..310dbaba55ff 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -805,7 +805,7 @@ static int msp_resume(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-static int msp_probe(struct i2c_client *client)
+static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct msp_state *state;
int (*thread_func)(void *data) = NULL;
@@ -815,7 +815,8 @@ static int msp_probe(struct i2c_client *client)
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
- snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+ if (!id)
+ strlcpy(client->name, "msp3400", sizeof(client->name));
if (msp_reset(client) == -1) {
v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
@@ -864,9 +865,6 @@ static int msp_probe(struct i2c_client *client)
msp_revision = (state->rev1 & 0x0f) + '@';
msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
msp_rom = state->rev2 & 0x1f;
- snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
- msp_family, msp_product,
- msp_revision, msp_hard, msp_rom);
/* Rev B=2, C=3, D=4, G=7 */
state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
msp_revision - '@';
@@ -931,7 +929,9 @@ static int msp_probe(struct i2c_client *client)
}
/* hello world :-) */
- v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+ v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n",
+ msp_family, msp_product,
+ msp_revision, msp_hard, msp_rom,
client->addr << 1, client->adapter->name);
v4l_info(client, "%s ", client->name);
if (state->has_nicam && state->has_radio)
@@ -987,6 +987,12 @@ static int msp_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id msp_id[] = {
+ { "msp3400", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, msp_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "msp3400",
.driverid = I2C_DRIVERID_MSP3400,
@@ -995,6 +1001,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.remove = msp_remove,
.suspend = msp_suspend,
.resume = msp_resume,
+ .id_table = msp_id,
};
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 3fb5f63df1e6..ee43499544c1 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -12,15 +12,12 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/log2.h>
+#include <linux/gpio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-#include <asm/gpio.h>
-#endif
-
/* mt9m001 i2c address 0x5d
* The platform has to define i2c_board_info
* and call i2c_register_board_info() */
@@ -372,7 +369,7 @@ static int mt9m001_set_register(struct soc_camera_device *icd,
}
#endif
-const struct v4l2_queryctrl mt9m001_controls[] = {
+static const struct v4l2_queryctrl mt9m001_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -620,7 +617,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
soc_camera_video_stop(&mt9m001->icd);
}
-static int mt9m001_probe(struct i2c_client *client)
+static int mt9m001_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
struct soc_camera_device *icd;
@@ -696,12 +694,19 @@ static int mt9m001_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id mt9m001_id[] = {
+ { "mt9m001", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
static struct i2c_driver mt9m001_i2c_driver = {
.driver = {
.name = "mt9m001",
},
.probe = mt9m001_probe,
.remove = mt9m001_remove,
+ .id_table = mt9m001_id,
};
static int __init mt9m001_mod_init(void)
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index d4b9e2744343..1658fe590392 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -13,15 +13,12 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/log2.h>
+#include <linux/gpio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-#include <asm/gpio.h>
-#endif
-
/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
* The platform has to define i2c_board_info
* and call i2c_register_board_info() */
@@ -91,7 +88,7 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
struct mt9v022 {
struct i2c_client *client;
struct soc_camera_device icd;
- int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
int switch_gpio;
u16 chip_control;
unsigned char datawidth;
@@ -452,7 +449,7 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
}
#endif
-const struct v4l2_queryctrl mt9v022_controls[] = {
+static const struct v4l2_queryctrl mt9v022_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -745,7 +742,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
soc_camera_video_stop(&mt9v022->icd);
}
-static int mt9v022_probe(struct i2c_client *client)
+static int mt9v022_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct mt9v022 *mt9v022;
struct soc_camera_device *icd;
@@ -818,12 +816,19 @@ static int mt9v022_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id mt9v022_id[] = {
+ { "mt9v022", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
static struct i2c_driver mt9v022_i2c_driver = {
.driver = {
.name = "mt9v022",
},
.probe = mt9v022_probe,
.remove = mt9v022_remove,
+ .id_table = mt9v022_id,
};
static int __init mt9v022_mod_init(void)
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 158b3d0c6532..4482b2c72ced 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -1,6 +1,8 @@
config VIDEO_PVRUSB2
tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C
+ depends on VIDEO_MEDIA # Avoids pvrusb = Y / DVB = M
+ depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -9,6 +11,7 @@ config VIDEO_PVRUSB2
select VIDEO_CX25840
select VIDEO_MSP3400
select VIDEO_WM8775
+ select VIDEO_CS53L32A
---help---
This is a video4linux driver for Conexant 23416 based
usb2 personal video recorder devices.
@@ -16,32 +19,6 @@ config VIDEO_PVRUSB2
To compile this driver as a module, choose M here: the
module will be called pvrusb2
-config VIDEO_PVRUSB2_ONAIR_CREATOR
- bool "pvrusb2 driver support for OnAir Creator model"
- depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- select VIDEO_SAA711X
- select VIDEO_CS53L32A
- ---help---
-
- This option enables support for the OnAir Creator USB tuner
- device. This is a hybrid device, however currently only
- analog mode is supported.
-
- If you are in doubt, say Y.
-
-config VIDEO_PVRUSB2_ONAIR_USB2
- bool "pvrusb2 driver support for OnAir USB2 model"
- depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- select VIDEO_SAA711X
- select VIDEO_CS53L32A
- ---help---
-
- This option enables support for the OnAir USB2 tuner device
- (also known as the Sasem tuner). This is a hybrid device,
- however currently only analog mode is supported.
-
- If you are in doubt, say Y.
-
config VIDEO_PVRUSB2_SYSFS
bool "pvrusb2 sysfs support (EXPERIMENTAL)"
default y
@@ -59,29 +36,23 @@ config VIDEO_PVRUSB2_SYSFS
Note: This feature is experimental and subject to change.
config VIDEO_PVRUSB2_DVB
- bool "pvrusb2 DVB support (EXPERIMENTAL)"
- default n
+ bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)"
+ default y
depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
- select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
- select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
---help---
- This option enables compilation of a DVB interface for the
- pvrusb2 driver. Currently this is very very experimental.
- It is also limiting - the DVB interface can only access the
- digital side of hybrid devices, and there are going to be
- issues if you attempt to mess with the V4L side at the same
- time. Don't turn this on unless you know what you are
- doing.
-
- If you are in doubt, say N.
+ This option enables a DVB interface for the pvrusb2 driver.
+ If your device does not support digital television, this
+ feature will have no affect on the driver's operation.
- Note: This feature is very experimental and might break
+ If you are in doubt, say Y.
config VIDEO_PVRUSB2_DEBUGIFC
bool "pvrusb2 debug interface"
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 5b3083c89aa9..4fda2de69ab7 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -16,5 +16,6 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index 11537ddf8aa3..707d2d9635d7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -54,6 +54,7 @@ extern int pvrusb2_debug;
#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */
#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */
#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */
+#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 3a141d93e1a9..5bf6d8fda1f9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -153,7 +153,6 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = {
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
/*------------------------------------------------------------------------*/
/* OnAir Creator */
@@ -212,11 +211,9 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = {
.dvb_props = &pvr2_onair_creator_fe_props,
#endif
};
-#endif
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
/*------------------------------------------------------------------------*/
/* OnAir USB 2.0 */
@@ -274,7 +271,6 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
.dvb_props = &pvr2_onair_usb2_fe_props,
#endif
};
-#endif
@@ -497,14 +493,10 @@ struct usb_device_id pvr2_device_table[] = {
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
{ USB_DEVICE(0x1164, 0x0602),
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
{ USB_DEVICE(0x11ba, 0x1003),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
-#endif
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
{ USB_DEVICE(0x11ba, 0x1001),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
-#endif
{ USB_DEVICE(0x2040, 0x7300),
.driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
{ USB_DEVICE(0x2040, 0x7500),
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
index 6504c97e0bbc..6ec4bf81fc7f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -21,6 +21,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include "dvbdev.h"
+#include "pvrusb2-debug.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
@@ -35,7 +36,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
struct pvr2_buffer *bp;
struct pvr2_stream *stream;
- printk(KERN_DEBUG "dvb thread started\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started");
set_freezable();
stream = adap->channel.stream->stream;
@@ -82,7 +83,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
/* If we get here and ret is < 0, then an error has occurred.
Probably would be a good idea to communicate that to DVB core... */
- printk(KERN_DEBUG "dvb thread stopped\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped");
return 0;
}
@@ -210,7 +211,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
do {
if (onoff) {
if (!adap->feedcount) {
- printk(KERN_DEBUG "start feeding\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED,
+ "start feeding demux");
ret = pvr2_dvb_stream_start(adap);
if (ret < 0) break;
}
@@ -218,7 +220,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
} else if (adap->feedcount > 0) {
(adap->feedcount)--;
if (!adap->feedcount) {
- printk(KERN_DEBUG "stop feeding\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED,
+ "stop feeding demux");
pvr2_dvb_stream_end(adap);
}
}
@@ -230,15 +233,13 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n",
- dvbdmxfeed->pid, dvbdmxfeed->type);
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid);
return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1);
}
static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n",
- dvbdmxfeed->pid, dvbdmxfeed->type);
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid);
return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0);
}
@@ -259,7 +260,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
&adap->channel.hdw->usb_dev->dev,
adapter_nr);
if (ret < 0) {
- err("dvb_register_adapter failed: error %d", ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_register_adapter failed: error %d", ret);
goto err;
}
adap->dvb_adap.priv = adap;
@@ -276,7 +278,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
ret = dvb_dmx_init(&adap->demux);
if (ret < 0) {
- err("dvb_dmx_init failed: error %d", ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_dmx_init failed: error %d", ret);
goto err_dmx;
}
@@ -286,7 +289,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
if (ret < 0) {
- err("dvb_dmxdev_init failed: error %d", ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_dmxdev_init failed: error %d", ret);
goto err_dmx_dev;
}
@@ -304,7 +308,7 @@ err:
static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
{
- printk(KERN_DEBUG "unregistering DVB devices\n");
+ pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices");
dvb_net_release(&adap->dvb_net);
adap->demux.dmx.close(&adap->demux.dmx);
dvb_dmxdev_release(&adap->dmxdev);
@@ -320,7 +324,7 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
int ret = 0;
if (dvb_props == NULL) {
- err("fe_props not defined!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!");
return -EINVAL;
}
@@ -328,13 +332,15 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
&adap->channel,
(1 << PVR2_CVAL_INPUT_DTV));
if (ret) {
- err("failed to grab control of dtv input (code=%d)",
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "failed to grab control of dtv input (code=%d)",
ret);
return ret;
}
if (dvb_props->frontend_attach == NULL) {
- err("frontend_attach not defined!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend_attach not defined!");
ret = -EINVAL;
goto done;
}
@@ -342,7 +348,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
- err("frontend registration failed!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend registration failed!");
dvb_frontend_detach(adap->fe);
adap->fe = NULL;
ret = -ENODEV;
@@ -359,7 +366,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
} else {
- err("no frontend was attached!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "no frontend was attached!");
ret = -ENODEV;
return ret;
}
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 416d05d4a969..435c083cc542 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1450,19 +1450,19 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
/* ----------------------------------------------------------------------- */
-static int saa7115_probe(struct i2c_client *client)
+static int saa7115_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa711x_state *state;
int i;
char name[17];
- u8 chip_id;
+ char chip_id;
+ int autodetect = !id || id->driver_data == 1;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- snprintf(client->name, sizeof(client->name) - 1, "saa7115");
-
for (i = 0; i < 0x0f; i++) {
saa711x_write(client, 0, i);
name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
@@ -1471,8 +1471,7 @@ static int saa7115_probe(struct i2c_client *client)
}
name[i] = '\0';
- saa711x_write(client, 0, 5);
- chip_id = saa711x_read(client, 0) & 0x0f;
+ chip_id = name[5];
/* Check whether this chip is part of the saa711x series */
if (memcmp(name, "1f711", 5)) {
@@ -1481,8 +1480,14 @@ static int saa7115_probe(struct i2c_client *client)
return -ENODEV;
}
- snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
- v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
+ /* Safety check */
+ if (!autodetect && id->name[6] != chip_id) {
+ v4l_warn(client, "found saa711%c while %s was expected\n",
+ chip_id, id->name);
+ }
+ snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
+ v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
+ client->addr << 1, client->adapter->name);
state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
i2c_set_clientdata(client, state);
@@ -1498,19 +1503,19 @@ static int saa7115_probe(struct i2c_client *client)
state->hue = 0;
state->sat = 64;
switch (chip_id) {
- case 1:
+ case '1':
state->ident = V4L2_IDENT_SAA7111;
break;
- case 3:
+ case '3':
state->ident = V4L2_IDENT_SAA7113;
break;
- case 4:
+ case '4':
state->ident = V4L2_IDENT_SAA7114;
break;
- case 5:
+ case '5':
state->ident = V4L2_IDENT_SAA7115;
break;
- case 8:
+ case '8':
state->ident = V4L2_IDENT_SAA7118;
break;
default:
@@ -1552,6 +1557,17 @@ static int saa7115_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id saa7115_id[] = {
+ { "saa711x", 1 }, /* autodetect */
+ { "saa7111", 0 },
+ { "saa7113", 0 },
+ { "saa7114", 0 },
+ { "saa7115", 0 },
+ { "saa7118", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7115_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7115",
.driverid = I2C_DRIVERID_SAA711X,
@@ -1559,5 +1575,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.probe = saa7115_probe,
.remove = saa7115_remove,
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+ .id_table = saa7115_id,
};
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 06c88db656b4..79d11a658bdf 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -661,7 +661,8 @@ static int saa7127_command(struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-static int saa7127_probe(struct i2c_client *client)
+static int saa7127_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa7127_state *state;
struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
@@ -671,8 +672,6 @@ static int saa7127_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- snprintf(client->name, sizeof(client->name) - 1, "saa7127");
-
v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
client->addr << 1);
@@ -740,11 +739,18 @@ static int saa7127_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static struct i2c_device_id saa7127_id[] = {
+ { "saa7127", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7127_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7127",
.driverid = I2C_DRIVERID_SAA7127,
.command = saa7127_command,
.probe = saa7127_probe,
.remove = saa7127_remove,
+ .id_table = saa7127_id,
};
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index e086f14d5663..83f076abce35 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -27,6 +27,7 @@ config VIDEO_SAA7134_ALSA
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
+ depends on HOTPLUG # due to FW_LOADER
select VIDEOBUF_DVB
select FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
@@ -35,9 +36,9 @@ config VIDEO_SAA7134_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select DVB_TDA827X if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index 9aff937ba7a5..3dbaa19a6d00 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 98375955a84b..b111903aa322 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -47,6 +47,9 @@ static char name_svideo[] = "S-Video";
/* ------------------------------------------------------------------ */
/* board config info */
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
struct saa7134_board saa7134_boards[] = {
[SAA7134_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
@@ -3087,7 +3090,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_type = TUNER_PHILIPS_TD1316, /* untested */
.radio_type = TUNER_TEA5767, /* untested */
.tuner_addr = ADDR_UNSET,
- .radio_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -4247,6 +4250,36 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
} },
},
+ [SAA7134_BOARD_BEHOLD_H6] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ .name = "Beholder BeholdTV H6",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ /* no DVB support for now */
+ /* .mpeg = SAA7134_MPEG_DVB, */
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5197,6 +5230,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x5ace,
.subdevice = 0x6193,
.driver_data = SAA7134_BOARD_BEHOLD_M6,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6191,
+ .driver_data = SAA7134_BOARD_BEHOLD_M6,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5246,6 +5285,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0xc900,
.driver_data = SAA7134_BOARD_VIDEOMATE_T750,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6290,
+ .driver_data = SAA7134_BOARD_BEHOLD_H6,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5577,20 +5622,87 @@ int saa7134_board_init1(struct saa7134_dev *dev)
return 0;
}
+static void saa7134_tuner_setup(struct saa7134_dev *dev)
+{
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ if (saa7134_boards[dev->board].radio_type != UNSET) {
+ tun_setup.type = saa7134_boards[dev->board].radio_type;
+ tun_setup.addr = saa7134_boards[dev->board].radio_addr;
+
+ tun_setup.mode_mask = T_RADIO;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) {
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.config = saa7134_boards[dev->board].tuner_config;
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ tun_setup.mode_mask = mode_mask;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ if (dev->tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+ &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(ctl));
+ memset(&ctl, 0, sizeof(ctl));
+
+ ctl.fname = XC2028_DEFAULT_FIRMWARE;
+ ctl.max_len = 64;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ctl.demod = XC3028_FE_ZARLINK456;
+ break;
+ default:
+ ctl.demod = XC3028_FE_OREN538;
+ ctl.mts = 1;
+ }
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+ }
+}
+
/* stuff which needs working i2c */
int saa7134_board_init2(struct saa7134_dev *dev)
{
unsigned char buf;
int board;
- struct tuner_setup tun_setup;
- tun_setup.config = 0;
- tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
switch (dev->board) {
case SAA7134_BOARD_BMK_MPEX_NOTUNER:
case SAA7134_BOARD_BMK_MPEX_TUNER:
dev->i2c_client.addr = 0x60;
- board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0)
+ board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
? SAA7134_BOARD_BMK_MPEX_NOTUNER
: SAA7134_BOARD_BMK_MPEX_TUNER;
if (board == dev->board)
@@ -5600,21 +5712,9 @@ int saa7134_board_init2(struct saa7134_dev *dev)
saa7134_boards[dev->board].name);
dev->tuner_type = saa7134_boards[dev->board].tuner_type;
- if (TUNER_ABSENT != dev->tuner_type) {
- tun_setup.mode_mask = T_RADIO |
- T_ANALOG_TV |
- T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
- tun_setup.tuner_callback = saa7134_tuner_callback;
-
- saa7134_i2c_call_clients(dev,
- TUNER_SET_TYPE_ADDR,
- &tun_setup);
- }
break;
case SAA7134_BOARD_MD7134:
- {
+ {
u8 subaddr;
u8 data[3];
int ret, tuner_t;
@@ -5667,30 +5767,8 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
- if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- dev->tda9887_conf = TDA9887_PRESENT |
- TDA9887_PORT1_ACTIVE |
- TDA9887_PORT2_ACTIVE;
-
- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
-
- tun_setup.mode_mask = T_RADIO |
- T_ANALOG_TV |
- T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
-
- saa7134_i2c_call_clients(dev,
- TUNER_SET_TYPE_ADDR, &tun_setup);
- }
break;
+ }
case SAA7134_BOARD_PHILIPS_EUROPA:
if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
/* Reconfigure board as Snake reference design */
@@ -5702,43 +5780,43 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ {
+
/* The Philips EUROPA based hybrid boards have the tuner connected through
* the channel decoder. We have to make it transparent to find it
*/
- {
u8 data[] = { 0x07, 0x02};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
-
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
- }
break;
+ }
case SAA7134_BOARD_PHILIPS_TIGER:
case SAA7134_BOARD_PHILIPS_TIGER_S:
- {
+ {
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
- if(dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+ if (dev->autodetected && (dev->eedata[0x49] == 0x50)) {
dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
printk(KERN_INFO "%s: Reconfigured board as %s\n",
dev->name, saa7134_boards[dev->board].name);
}
- if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = TUNER_PHILIPS_TDA8290;
- tun_setup.addr = 0x4b;
- tun_setup.config = 2;
+ if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+ dev->tuner_type = TUNER_PHILIPS_TDA8290;
+
+ saa7134_tuner_setup(dev);
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
data[2] = 0x68;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ /* Tuner setup is handled before I2C transfer.
+ Due to that, there's no need to do it later
+ */
+ return 0;
}
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
hauppauge_eeprom(dev, dev->eedata+0x80);
/* break intentionally omitted */
@@ -5751,52 +5829,55 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
case SAA7134_BOARD_CREATIX_CTX953:
+ {
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
- {
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_FLYDVB_TRIO:
- {
+ {
u8 data[] = { 0x3c, 0x33, 0x62};
struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ {
/* initialize analog mode */
- {
u8 data[] = { 0x3c, 0x33, 0x6a};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
case SAA7134_BOARD_CINERGY_HT_PCI:
+ {
/* initialize analog mode */
- {
u8 data[] = { 0x3c, 0x33, 0x68};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_KWORLD_ATSC110:
- {
- /* enable tuner */
- int i;
- static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
- dev->i2c_client.addr = 0x0a;
- for (i = 0; i < 5; i++)
- if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2))
- printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
- dev->name, i);
- }
+ {
+ /* enable tuner */
+ int i;
+ static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16,
+ 0x00, 0x14, 0x04, 0x17, 0x00 };
+ dev->i2c_client.addr = 0x0a;
+ for (i = 0; i < 5; i++)
+ if (2 != i2c_master_send(&dev->i2c_client,
+ &buffer[i*2], 2))
+ printk(KERN_WARNING
+ "%s: Unable to enable tuner(%i).\n",
+ dev->name, i);
break;
+ }
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
/* The T200 and the T200A share the same pci id. Consequently,
@@ -5821,7 +5902,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
- {
+ {
struct v4l2_priv_tun_config tea5767_cfg;
struct tea5767_ctrl ctl;
@@ -5832,34 +5913,11 @@ int saa7134_board_init2(struct saa7134_dev *dev)
tea5767_cfg.tuner = TUNER_TEA5767;
tea5767_cfg.priv = &ctl;
saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
- }
break;
}
+ } /* switch() */
- if (dev->tuner_type == TUNER_XC2028) {
- struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
-
- memset(&xc2028_cfg, 0, sizeof(ctl));
- memset(&ctl, 0, sizeof(ctl));
-
- ctl.fname = XC2028_DEFAULT_FIRMWARE;
- ctl.max_len = 64;
-
- switch (dev->board) {
- case SAA7134_BOARD_AVERMEDIA_A16D:
- ctl.demod = XC3028_FE_ZARLINK456;
- break;
- default:
- ctl.demod = XC3028_FE_OREN538;
- ctl.mts = 1;
- }
-
- xc2028_cfg.tuner = TUNER_XC2028;
- xc2028_cfg.priv = &ctl;
-
- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
- }
+ saa7134_tuner_setup(dev);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index eec127864fe3..2c19cd0113c8 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -864,7 +864,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct saa7134_dev *dev;
struct saa7134_mpeg_ops *mops;
int err;
- int mask;
if (saa7134_devcount == SAA7134_MAXBOARDS)
return -ENOMEM;
@@ -1065,11 +1064,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (TUNER_ABSENT != dev->tuner_type)
saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
- if (card(dev).gpiomask != 0) {
- mask = card(dev).gpiomask;
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, 0);
- }
return 0;
fail4:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 2d16be2259db..469f93aac008 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -538,19 +538,23 @@ static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
return 0;
}
-static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *cdec_conf,
- struct tda827x_config *tuner_conf)
+static int configure_tda827x_fe(struct saa7134_dev *dev,
+ struct tda1004x_config *cdec_conf,
+ struct tda827x_config *tuner_conf)
{
dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (cdec_conf->i2c_gate)
dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
- if (dvb_attach(tda827x_attach, dev->dvb.frontend, cdec_conf->tuner_address,
- &dev->i2c_adap, tuner_conf) == NULL) {
- wprintk("no tda827x tuner found at addr: %02x\n",
+ if (dvb_attach(tda827x_attach, dev->dvb.frontend,
+ cdec_conf->tuner_address,
+ &dev->i2c_adap, tuner_conf))
+ return 0;
+
+ wprintk("no tda827x tuner found at addr: %02x\n",
cdec_conf->tuner_address);
- }
}
+ return -EINVAL;
}
/* ------------------------------------------------------------------ */
@@ -997,7 +1001,9 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
- configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
@@ -1022,36 +1028,52 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_KWORLD_DVBT_210:
- configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_TIGER:
- configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &philips_tiger_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PINNACLE_PCTV_310i:
- configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1);
+ if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
+ &tda827x_cfg_1) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
- configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1);
+ if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
+ &tda827x_cfg_1) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_FLYDVBT_LR301:
- configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_FLYDVB_TRIO:
- if(! use_frontend) { /* terrestrial */
- configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0);
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &lifeview_trio_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
+ goto dettach_frontend;
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
0x08, 0, 0) == NULL) {
wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
+ goto dettach_frontend;
}
}
}
@@ -1067,15 +1089,20 @@ static int dvb_init(struct saa7134_dev *dev)
&ads_duo_cfg) == NULL) {
wprintk("no tda827x tuner found at addr: %02x\n",
ads_tech_duo_config.tuner_address);
+ goto dettach_frontend;
}
}
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
- configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_MEDION_MD8800_QUADRO:
if (!use_frontend) { /* terrestrial */
- configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach,
&flydvbs, &dev->i2c_adap);
@@ -1086,16 +1113,20 @@ static int dvb_init(struct saa7134_dev *dev)
struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
if (dvb_attach(tda826x_attach, dev->dvb.frontend,
- 0x60, &dev->i2c_adap, 0) == NULL)
+ 0x60, &dev->i2c_adap, 0) == NULL) {
wprintk("%s: Medion Quadro, no tda826x "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
if (dev_id != 0x08) {
/* we need to open the i2c gate (we know it exists) */
fe->ops.i2c_gate_ctrl(fe, 1);
if (dvb_attach(isl6405_attach, fe,
- &dev->i2c_adap, 0x08, 0, 0) == NULL)
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: Medion Quadro, no ISL6405 "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
if (dev_id == 0x07) {
/* fire up the 2nd section of the LNB supply since
we can't do this from the other section */
@@ -1117,19 +1148,17 @@ static int dvb_init(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
+ if (dev->dvb.frontend)
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
NULL, DVB_PLL_TDHU2);
- }
break;
case SAA7134_BOARD_KWORLD_ATSC110:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
+ if (dev->dvb.frontend)
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D);
- }
break;
case SAA7134_BOARD_FLYDVBS_LR300:
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
@@ -1138,10 +1167,12 @@ static int dvb_init(struct saa7134_dev *dev)
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
+ goto dettach_frontend;
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: No ISL6421 found!\n", __func__);
+ goto dettach_frontend;
}
}
break;
@@ -1168,43 +1199,65 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
- configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &cinergy_ht_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_CINERGY_HT_PCI:
- configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_TIGER_S:
- configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_ASUS_P7131_4871:
- configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
- configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &avermedia_super_007_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
- configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42);
+ if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
+ &tda827x_cfg_2_sw42) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_SNAKE:
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
- &dev->i2c_adap, 0) == NULL)
+ &dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
+ goto dettach_frontend;
+ }
if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
- &dev->i2c_adap, 0, 0) == NULL)
+ &dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: No lnbp21 found!\n", __func__);
+ goto dettach_frontend;
+ }
}
break;
case SAA7134_BOARD_CREATIX_CTX953:
- configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
- configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
dev->dvb.frontend = dvb_attach(mt352_attach,
@@ -1218,16 +1271,20 @@ static int dvb_init(struct saa7134_dev *dev)
if (dev->dvb.frontend) {
struct dvb_frontend *fe;
if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL)
+ &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
wprintk("%s: MD7134 DVB-S, no SD1878 "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
/* we need to open the i2c gate (we know it exists) */
fe = dev->dvb.frontend;
fe->ops.i2c_gate_ctrl(fe, 1);
if (dvb_attach(isl6405_attach, fe,
- &dev->i2c_adap, 0x08, 0, 0) == NULL)
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: MD7134 DVB-S, no ISL6405 "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
fe->ops.i2c_gate_ctrl(fe, 0);
dev->original_set_voltage = fe->ops.set_voltage;
fe->ops.set_voltage = md8800_set_voltage;
@@ -1254,10 +1311,7 @@ static int dvb_init(struct saa7134_dev *dev)
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->name);
- dvb_frontend_detach(dev->dvb.frontend);
- dvb_unregister_frontend(dev->dvb.frontend);
- dev->dvb.frontend = NULL;
- return -1;
+ goto dettach_frontend;
}
}
@@ -1282,6 +1336,12 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
}
return ret;
+
+dettach_frontend:
+ dvb_frontend_detach(dev->dvb.frontend);
+ dev->dvb.frontend = NULL;
+
+ return -1;
}
static int dvb_fini(struct saa7134_dev *dev)
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 2ccfaba0c490..d8af3863f2d3 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -324,8 +324,6 @@ static u32 functionality(struct i2c_adapter *adap)
static int attach_inform(struct i2c_client *client)
{
struct saa7134_dev *dev = client->adapter->algo_data;
- int tuner = dev->tuner_type;
- struct tuner_setup tun_setup;
d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->driver.name, client->addr, client->name);
@@ -346,46 +344,6 @@ static int attach_inform(struct i2c_client *client)
}
}
- if (!client->driver->command)
- return 0;
-
- if (saa7134_boards[dev->board].radio_type != UNSET) {
-
- tun_setup.type = saa7134_boards[dev->board].radio_type;
- tun_setup.addr = saa7134_boards[dev->board].radio_addr;
-
- if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) {
- tun_setup.mode_mask = T_RADIO;
-
- client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
-
- if (tuner != UNSET) {
- tun_setup.type = tuner;
- tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
- tun_setup.config = saa7134_boards[dev->board].tuner_config;
- tun_setup.tuner_callback = saa7134_tuner_callback;
-
- if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
-
- tun_setup.mode_mask = T_ANALOG_TV;
-
- client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
- }
-
- if (tuner == TUNER_TDA9887) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- client->driver->command(client, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
- }
-
-
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 767ff30832f2..919632b10aae 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -531,6 +531,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
break;
case SAA7134_BOARD_BEHOLD_607_9FM:
case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_H6:
snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
ir->get_key = get_key_beholdm6xx;
ir->ir_codes = ir_codes_behold;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index a0baf2d0ba7f..48e1a01718ec 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1634,7 +1634,7 @@ static int saa7134_s_fmt_overlay(struct file *file, void *priv,
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
int err;
- unsigned int flags;
+ unsigned long flags;
if (saa7134_no_overlay > 0) {
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 924ffd13637e..34ff0d4998f3 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -263,6 +263,7 @@ struct saa7134_format {
#define SAA7134_BOARD_VIDEOMATE_T750 139
#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+#define SAA7134_BOARD_BEHOLD_H6 142
#define SAA7134_MAXBOARDS 8
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index 53c5edbcf7ea..2220f9569941 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -1418,7 +1418,8 @@ static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
/* ----------------------------------------------------------------------- */
-static int saa717x_probe(struct i2c_client *client)
+static int saa717x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct saa717x_state *decoder;
u8 id = 0;
@@ -1428,8 +1429,6 @@ static int saa717x_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- snprintf(client->name, sizeof(client->name) - 1, "saa717x");
-
if (saa717x_write(client, 0x5a4, 0xfe) &&
saa717x_write(client, 0x5a5, 0x0f) &&
saa717x_write(client, 0x5a6, 0x00) &&
@@ -1506,6 +1505,12 @@ static int saa717x_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id saa717x_id[] = {
+ { "saa717x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa717x_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa717x",
.driverid = I2C_DRIVERID_SAA717X,
@@ -1513,4 +1518,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.probe = saa717x_probe,
.remove = saa717x_remove,
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+ .id_table = saa717x_id,
};
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 5748b1e1a128..7f9c7bcf3c85 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index 9276ed997388..b12c60cf5a09 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -30,6 +30,7 @@
#include <linux/kref.h>
#include <linux/usb.h>
+#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
@@ -245,6 +246,8 @@ static int stk_initialise(struct stk_camera *dev)
return -1;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+
/* sysfs functions */
/*FIXME cleanup this */
@@ -350,6 +353,10 @@ static void stk_remove_sysfs_files(struct video_device *vdev)
video_device_remove_file(vdev, &dev_attr_vflip);
}
+#else
+#define stk_create_sysfs_files(a)
+#define stk_remove_sysfs_files(a)
+#endif
/* *********************************************** */
/*
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index 6943b447a1bd..8f0100f67a91 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -840,7 +840,8 @@ static struct v4l2_int_device tcm825x_int_device = {
},
};
-static int tcm825x_probe(struct i2c_client *client)
+static int tcm825x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct tcm825x_sensor *sensor = &tcm825x;
int rval;
@@ -884,12 +885,19 @@ static int __exit tcm825x_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id tcm825x_id[] = {
+ { "tcm825x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tcm825x_id);
+
static struct i2c_driver tcm825x_i2c_driver = {
.driver = {
.name = TCM825X_NAME,
},
.probe = tcm825x_probe,
.remove = __exit_p(tcm825x_remove),
+ .id_table = tcm825x_id,
};
static struct tcm825x_sensor tcm825x = {
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index dc7b9c220b90..28ab9f9d760a 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -125,7 +125,8 @@ static int tlv320aic23b_command(struct i2c_client *client,
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int tlv320aic23b_probe(struct i2c_client *client)
+static int tlv320aic23b_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tlv320aic23b_state *state;
@@ -167,6 +168,11 @@ static int tlv320aic23b_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id tlv320aic23b_id[] = {
+ { "tlv320aic23b", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tlv320aic23b",
@@ -174,4 +180,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.command = tlv320aic23b_command,
.probe = tlv320aic23b_probe,
.remove = tlv320aic23b_remove,
+ .id_table = tlv320aic23b_id,
};
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 2b72e10e6b9f..198f0afb812e 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -33,6 +33,46 @@
#define PREFIX t->i2c->driver->driver.name
+/** This macro allows us to probe dynamically, avoiding static links */
+#ifdef CONFIG_MEDIA_ATTACH
+#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
+ int __r = -EINVAL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (int) __a(ARGS); \
+ symbol_put(FUNCTION); \
+ } else { \
+ printk(KERN_ERR "TUNER: Unable to find " \
+ "symbol "#FUNCTION"()\n"); \
+ } \
+ __r; \
+})
+
+static void tuner_detach(struct dvb_frontend *fe)
+{
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ symbol_put_addr(fe->ops.tuner_ops.release);
+ }
+ if (fe->ops.analog_ops.release) {
+ fe->ops.analog_ops.release(fe);
+ symbol_put_addr(fe->ops.analog_ops.release);
+ }
+}
+#else
+#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+static void tuner_detach(struct dvb_frontend *fe)
+{
+ if (fe->ops.tuner_ops.release)
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.analog_ops.release)
+ fe->ops.analog_ops.release(fe);
+}
+#endif
+
struct tuner {
/* device */
struct dvb_frontend fe;
@@ -56,7 +96,7 @@ struct tuner {
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
-#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
0x10,
#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
@@ -139,22 +179,6 @@ static void fe_set_params(struct dvb_frontend *fe,
fe_tuner_ops->set_analog_params(fe, params);
}
-static void fe_release(struct dvb_frontend *fe)
-{
- if (fe->ops.tuner_ops.release)
- fe->ops.tuner_ops.release(fe);
-
- /* DO NOT kfree(fe->analog_demod_priv)
- *
- * If we are in this function, analog_demod_priv contains a pointer
- * to struct tuner *t. This will be kfree'd in tuner_detach().
- *
- * Otherwise, fe->ops.analog_demod_ops->release will
- * handle the cleanup for analog demodulator modules.
- */
- fe->analog_demod_priv = NULL;
-}
-
static void fe_standby(struct dvb_frontend *fe)
{
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -191,7 +215,6 @@ static void tuner_status(struct dvb_frontend *fe);
static struct analog_demod_ops tuner_core_ops = {
.set_params = fe_set_params,
.standby = fe_standby,
- .release = fe_release,
.has_signal = fe_has_signal,
.set_config = fe_set_config,
.tuner_status = tuner_status
@@ -317,15 +340,6 @@ static void tuner_i2c_address_check(struct tuner *t)
tuner_warn("====================== WARNING! ======================\n");
}
-static void attach_tda829x(struct tuner *t)
-{
- struct tda829x_config cfg = {
- .lna_cfg = t->config,
- .tuner_callback = t->tuner_callback,
- };
- tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
-}
-
static struct xc5000_config xc5000_cfg;
static void set_type(struct i2c_client *c, unsigned int type,
@@ -356,25 +370,35 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
/* discard private data, in case set_type() was previously called */
- if (analog_ops->release)
- analog_ops->release(&t->fe);
+ tuner_detach(&t->fe);
+ t->fe.analog_demod_priv = NULL;
switch (t->type) {
case TUNER_MT2032:
- microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ if (!dvb_attach(microtune_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
break;
case TUNER_PHILIPS_TDA8290:
{
- attach_tda829x(t);
+ struct tda829x_config cfg = {
+ .lna_cfg = t->config,
+ .tuner_callback = t->tuner_callback,
+ };
+ if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
+ t->i2c->addr, &cfg))
+ goto attach_failed;
break;
}
case TUNER_TEA5767:
- if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+ if (!dvb_attach(tea5767_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr))
goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_TEA5761:
- if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+ if (!dvb_attach(tea5761_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr))
goto attach_failed;
t->mode_mask = T_RADIO;
break;
@@ -388,8 +412,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
- t->type))
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed;
break;
case TUNER_PHILIPS_TD1316:
@@ -397,9 +421,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[1] = 0xdc;
buffer[2] = 0x86;
buffer[3] = 0xa4;
- i2c_master_send(c,buffer,4);
- if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type))
+ i2c_master_send(c, buffer, 4);
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed;
break;
case TUNER_XC2028:
@@ -409,12 +433,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
.i2c_addr = t->i2c->addr,
.callback = t->tuner_callback,
};
- if (!xc2028_attach(&t->fe, &cfg))
+ if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
goto attach_failed;
break;
}
case TUNER_TDA9887:
- tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ if (!dvb_attach(tda9887_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
break;
case TUNER_XC5000:
{
@@ -422,9 +448,10 @@ static void set_type(struct i2c_client *c, unsigned int type,
xc5000_cfg.i2c_address = t->i2c->addr;
xc5000_cfg.if_khz = 5380;
- xc5000_cfg.priv = c->adapter->algo_data;
xc5000_cfg.tuner_callback = t->tuner_callback;
- if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg))
+ if (!dvb_attach(xc5000_attach,
+ &t->fe, t->i2c->adapter, &xc5000_cfg,
+ c->adapter->algo_data))
goto attach_failed;
xc_tuner_ops = &t->fe.ops.tuner_ops;
@@ -433,8 +460,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
break;
}
default:
- if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type))
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed;
break;
@@ -442,12 +469,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
if ((NULL == analog_ops->set_params) &&
(fe_tuner_ops->set_analog_params)) {
+
strlcpy(t->i2c->name, fe_tuner_ops->info.name,
sizeof(t->i2c->name));
t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops,
sizeof(struct analog_demod_ops));
+
} else {
strlcpy(t->i2c->name, analog_ops->info.name,
sizeof(t->i2c->name));
@@ -645,8 +674,8 @@ static void tuner_status(struct dvb_frontend *fe)
{
struct tuner *t = fe->analog_demod_priv;
unsigned long freq, freq_fraction;
- struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+ struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
const char *p;
switch (t->mode) {
@@ -730,8 +759,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (tuner_debug>1)
+ if (tuner_debug > 1) {
v4l_i2c_print_ioctl(client,cmd);
+ printk("\n");
+ }
switch (cmd) {
/* --- configuration --- */
@@ -1073,7 +1104,8 @@ static void tuner_lookup(struct i2c_adapter *adap,
/* During client attach, set_type is called by adapter's attach_inform callback.
set_type must then be completed by tuner_probe.
*/
-static int tuner_probe(struct i2c_client *client)
+static int tuner_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tuner *t;
struct tuner *radio;
@@ -1083,7 +1115,6 @@ static int tuner_probe(struct i2c_client *client)
if (NULL == t)
return -ENOMEM;
t->i2c = client;
- strlcpy(client->name, "(tuner unset)", sizeof(client->name));
i2c_set_clientdata(client, t);
t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO;
@@ -1111,8 +1142,9 @@ static int tuner_probe(struct i2c_client *client)
if (!no_autodetect) {
switch (client->addr) {
case 0x10:
- if (tea5761_autodetection(t->i2c->adapter,
- t->i2c->addr) >= 0) {
+ if (tuner_symbol_probe(tea5761_autodetection,
+ t->i2c->adapter,
+ t->i2c->addr) >= 0) {
t->type = TUNER_TEA5761;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -1131,8 +1163,8 @@ static int tuner_probe(struct i2c_client *client)
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda829x_probe(t->i2c->adapter,
- t->i2c->addr) == 0) {
+ if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
+ t->i2c->addr) >= 0) {
tuner_dbg("tda829x detected\n");
} else {
/* Default is being tda9887 */
@@ -1144,8 +1176,9 @@ static int tuner_probe(struct i2c_client *client)
}
break;
case 0x60:
- if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
- != EINVAL) {
+ if (tuner_symbol_probe(tea5767_autodetection,
+ t->i2c->adapter, t->i2c->addr)
+ >= 0) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -1233,18 +1266,32 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
static int tuner_remove(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (analog_ops->release)
- analog_ops->release(&t->fe);
+ tuner_detach(&t->fe);
+ t->fe.analog_demod_priv = NULL;
list_del(&t->list);
kfree(t);
+
+ /* The probing code has overwritten the device name, restore it so
+ that reloading the driver will work. Ideally the device name
+ should not be overwritten in the first place, but for now that
+ will do. */
+ strlcpy(client->name, "tuner", I2C_NAME_SIZE);
return 0;
}
/* ----------------------------------------------------------------------- */
+/* This driver supports many devices and the idea is to let the driver
+ detect which device is present. So rather than listing all supported
+ devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id tuner_id[] = {
+ { "tuner", }, /* autodetect */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tuner_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tuner",
.driverid = I2C_DRIVERID_TUNER,
@@ -1254,6 +1301,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.suspend = tuner_suspend,
.resume = tuner_resume,
.legacy_probe = tuner_legacy_probe,
+ .id_table = tuner_id,
};
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index f29a2cd0f2f2..c77914d99d15 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1461,7 +1461,7 @@ static struct CHIPDESC chiplist[] = {
/* ---------------------------------------------------------------------- */
/* i2c registration */
-static int chip_probe(struct i2c_client *client)
+static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct CHIPSTATE *chip;
struct CHIPDESC *desc;
@@ -1505,7 +1505,8 @@ static int chip_probe(struct i2c_client *client)
}
/* fill required data structures */
- strcpy(client->name, desc->name);
+ if (!id)
+ strlcpy(client->name, desc->name, I2C_NAME_SIZE);
chip->type = desc-chiplist;
chip->shadow.count = desc->registers+1;
chip->prevmode = -1;
@@ -1830,6 +1831,15 @@ static int chip_legacy_probe(struct i2c_adapter *adap)
return 0;
}
+/* This driver supports many devices and the idea is to let the driver
+ detect which device is present. So rather than listing all supported
+ devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id chip_id[] = {
+ { "tvaudio", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, chip_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tvaudio",
.driverid = I2C_DRIVERID_TVAUDIO,
@@ -1837,6 +1847,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.probe = chip_probe,
.remove = chip_remove,
.legacy_probe = chip_legacy_probe,
+ .id_table = chip_id,
};
/*
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 3cf8a8e801e5..9da0e1807ffb 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -319,10 +319,12 @@ audioIC[] =
{AUDIO_CHIP_INTERNAL, "CX25843"},
{AUDIO_CHIP_INTERNAL, "CX23418"},
{AUDIO_CHIP_INTERNAL, "CX23885"},
- /* 40-42 */
+ /* 40-44 */
{AUDIO_CHIP_INTERNAL, "CX23888"},
{AUDIO_CHIP_INTERNAL, "SAA7131"},
{AUDIO_CHIP_INTERNAL, "CX23887"},
+ {AUDIO_CHIP_INTERNAL, "SAA7164"},
+ {AUDIO_CHIP_INTERNAL, "AU8522"},
};
/* This list is supplied by Hauppauge. Thanks! */
@@ -341,8 +343,10 @@ static const char *decoderIC[] = {
"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
/* 30-34 */
"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
- /* 35-37 */
- "SAA7131", "CX25837", "CX23887"
+ /* 35-39 */
+ "SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A",
+ /* 40-42 */
+ "SAA7164", "CX23885B", "AU8522"
};
static int hasRadioTuner(int tunerType)
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index bd201397a2ac..b4628874933b 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -195,7 +195,8 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
-static int upd64031a_probe(struct i2c_client *client)
+static int upd64031a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct upd64031a_state *state;
int i;
@@ -227,6 +228,11 @@ static int upd64031a_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id upd64031a_id[] = {
+ { "upd64031a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, upd64031a_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "upd64031a",
@@ -234,4 +240,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.command = upd64031a_command,
.probe = upd64031a_probe,
.remove = upd64031a_remove,
+ .id_table = upd64031a_id,
};
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 2d9a88f70c85..9521ce004dcc 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -172,7 +172,8 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
-static int upd64083_probe(struct i2c_client *client)
+static int upd64083_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct upd64083_state *state;
int i;
@@ -204,6 +205,11 @@ static int upd64083_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id upd64083_id[] = {
+ { "upd64083", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, upd64083_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "upd64083",
@@ -211,4 +217,5 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.command = upd64083_command,
.probe = upd64083_probe,
.remove = upd64083_remove,
+ .id_table = upd64083_id,
};
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 64819353276a..17f542dfb366 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -70,12 +70,6 @@
#define VICAM_HEADER_SIZE 64
-#define clamp( x, l, h ) max_t( __typeof__( x ), \
- ( l ), \
- min_t( __typeof__( x ), \
- ( h ), \
- ( x ) ) )
-
/* Not sure what all the bytes in these char
* arrays do, but they're necessary to make
* the camera work.
diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile
index 9ac92a80c645..338718750945 100644
--- a/drivers/media/video/usbvision/Makefile
+++ b/drivers/media/video/usbvision/Makefile
@@ -3,3 +3,4 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-
obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 7cc42c1da457..e9dd996fd5df 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -710,7 +710,8 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
/* Helper function for I2C legacy drivers */
int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
- const char *name, int (*probe)(struct i2c_client *))
+ const char *name,
+ int (*probe)(struct i2c_client *, const struct i2c_device_id *))
{
struct i2c_client *client;
int err;
@@ -724,7 +725,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
client->driver = driver;
strlcpy(client->name, name, sizeof(client->name));
- err = probe(client);
+ err = probe(client, NULL);
if (err == 0) {
i2c_attach_client(client);
} else {
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index 282c81403c97..a1f76ee032e7 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -121,7 +121,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int vp27smpx_probe(struct i2c_client *client)
+static int vp27smpx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct vp27smpx_state *state;
@@ -129,8 +130,6 @@ static int vp27smpx_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
-
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -153,11 +152,18 @@ static int vp27smpx_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct i2c_device_id vp27smpx_id[] = {
+ { "vp27smpx", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "vp27smpx",
.driverid = I2C_DRIVERID_VP27SMPX,
.command = vp27smpx_command,
.probe = vp27smpx_probe,
.remove = vp27smpx_remove,
+ .id_table = vp27smpx_id,
};
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 31795b4f8b63..fc50299caa36 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -261,7 +261,8 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
-static int wm8739_probe(struct i2c_client *client)
+static int wm8739_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct wm8739_state *state;
@@ -312,11 +313,18 @@ static int wm8739_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id wm8739_id[] = {
+ { "wm8739", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8739_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "wm8739",
.driverid = I2C_DRIVERID_WM8739,
.command = wm8739_command,
.probe = wm8739_probe,
.remove = wm8739_remove,
+ .id_table = wm8739_id,
};
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 869f9e7946b6..506378a508b9 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -159,7 +159,8 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int wm8775_probe(struct i2c_client *client)
+static int wm8775_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct wm8775_state *state;
@@ -215,11 +216,18 @@ static int wm8775_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id wm8775_id[] = {
+ { "wm8775", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8775_id);
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "wm8775",
.driverid = I2C_DRIVERID_WM8775,
.command = wm8775_command,
.probe = wm8775_probe,
.remove = wm8775_remove,
+ .id_table = wm8775_id,
};
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 363dd2b9475c..e5c4e9f5193f 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -38,7 +38,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index 7b60533efe45..37629ffd34c3 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
-#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
@@ -47,6 +46,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
+#include <asm/byteorder.h>
#include <asm/io.h>
#include "videocodec.h"
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 0134bec1e399..345c77e46837 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -52,7 +52,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
@@ -74,6 +73,7 @@
#include <media/v4l2-common.h>
#include "videocodec.h"
+#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index 328ed6e7ac6a..870bc5a70e3f 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -180,6 +180,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer,
}
static const struct file_operations zoran_operations = {
+ .owner = THIS_MODULE,
.open = zoran_open,
.read = seq_read,
.write = zoran_write,
@@ -195,10 +196,8 @@ zoran_proc_init (struct zoran *zr)
char name[8];
snprintf(name, 7, "zoran%d", zr->id);
- if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) {
- zr->zoran_proc->data = zr;
- zr->zoran_proc->owner = THIS_MODULE;
- zr->zoran_proc->proc_fops = &zoran_operations;
+ zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr);
+ if (zr->zoran_proc != NULL) {
dprintk(2,
KERN_INFO
"%s: procfs entry /proc/%s allocated. data=%p\n",
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index a95314897402..81483de8c0fd 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -371,7 +371,7 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
/* connect the i2o_block_request to the request */
if (!req->special) {
ireq = i2o_block_request_alloc();
- if (unlikely(IS_ERR(ireq))) {
+ if (IS_ERR(ireq)) {
osm_debug("unable to allocate i2o_block_request!\n");
return BLKPREP_DEFER;
}
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 6fdd072201f9..54a3016ff45d 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -1893,13 +1893,11 @@ static int i2o_proc_create_entries(struct proc_dir_entry *dir,
struct proc_dir_entry *tmp;
while (i2o_pe->name) {
- tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir);
+ tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir,
+ i2o_pe->fops, data);
if (!tmp)
return -1;
- tmp->data = data;
- tmp->proc_fops = i2o_pe->fops;
-
i2o_pe++;
}
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index f6f2d960cadb..ef8a492766a7 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -132,7 +132,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
if (iter >= MAX_ASIC_ISR_LOOPS)
printk(KERN_ERR "%s: interrupt processing overrun\n",
- __FUNCTION__);
+ __func__);
}
static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
@@ -409,7 +409,7 @@ int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio)
return asic3_get_gpio_d(asic, Status) & mask;
default:
printk(KERN_ERR "%s: invalid GPIO value 0x%x",
- __FUNCTION__, gpio);
+ __func__, gpio);
return -EINVAL;
}
}
@@ -437,7 +437,7 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val)
return;
default:
printk(KERN_ERR "%s: invalid GPIO value 0x%x",
- __FUNCTION__, gpio);
+ __func__, gpio);
return;
}
}
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index 4edc120a6359..633cbba072f0 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -132,8 +132,9 @@ static struct ds1wm_platform_data ds1wm_pdata = {
.disable = ds1wm_disable,
};
-static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift)
+static int ds1wm_device_add(struct platform_device *pasic3_pdev, int bus_shift)
{
+ struct device *pasic3_dev = &pasic3_pdev->dev;
struct pasic3_data *asic = pasic3_dev->driver_data;
struct platform_device *pdev;
int ret;
@@ -144,8 +145,8 @@ static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift)
return -ENOMEM;
}
- ret = platform_device_add_resources(pdev, pdev->resource,
- pdev->num_resources);
+ ret = platform_device_add_resources(pdev, pasic3_pdev->resource,
+ pasic3_pdev->num_resources);
if (ret < 0) {
dev_dbg(pasic3_dev, "failed to add DS1WM resources\n");
goto exit_pdev_put;
@@ -207,7 +208,7 @@ static int __init pasic3_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ret = ds1wm_device_add(dev, asic->bus_shift);
+ ret = ds1wm_device_add(pdev, asic->bus_shift);
if (ret < 0)
dev_warn(dev, "failed to register DS1WM\n");
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 6e655b4c6682..2fe64734d8af 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -349,11 +349,11 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
mode &= 3; /* get current power mode */
if (unit >= ARRAY_SIZE(sm->unit_power)) {
- dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit);
+ dev_err(dev, "%s: bad unit %d\n", __func__, unit);
goto already;
}
- dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit,
+ dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __func__, unit,
sm->unit_power[unit], to);
if (to == 0 && sm->unit_power[unit] == 0) {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 297a48f85446..636af2862308 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -140,6 +140,7 @@ config ACER_WMI
depends on EXPERIMENTAL
depends on ACPI
depends on LEDS_CLASS
+ depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
select ACPI_WMI
@@ -160,6 +161,7 @@ config ASUS_LAPTOP
depends on ACPI
depends on EXPERIMENTAL && !ACPI_ASUS
depends on LEDS_CLASS
+ depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
---help---
This is the new Linux driver for Asus laptops. It may also support some
@@ -241,10 +243,13 @@ config SONYPI_COMPAT
config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on X86 && ACPI
+ select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
- depends on INPUT
+ select INPUT
+ select NEW_LEDS
+ select LEDS_CLASS
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -344,6 +349,7 @@ config ATMEL_SSC
config INTEL_MENLOW
tristate "Thermal Management driver for Intel menlow platform"
depends on ACPI_THERMAL
+ select THERMAL
depends on X86
---help---
ACPI thermal management enhancement driver on
@@ -351,6 +357,19 @@ config INTEL_MENLOW
If unsure, say N.
+config EEEPC_LAPTOP
+ tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+ depends on X86
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on HWMON
+ depends on EXPERIMENTAL
+ ---help---
+ This driver supports the Fn-Fx keys on Eee PC laptops.
+ It also adds the ability to switch camera/wlan on/off.
+
+ If you have an Eee PC laptop, say Y or M here.
+
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
default n
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5914da434854..1952875a272e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,7 +7,8 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
-obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
new file mode 100644
index 000000000000..6d727609097f
--- /dev/null
+++ b/drivers/misc/eeepc-laptop.c
@@ -0,0 +1,666 @@
+/*
+ * eepc-laptop.c - Asus Eee PC extras
+ *
+ * Based on asus_acpi.c as patched for the Eee PC by Asus:
+ * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
+ * Based on eee.c from eeepc-linux
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <linux/uaccess.h>
+
+#define EEEPC_LAPTOP_VERSION "0.1"
+
+#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
+#define EEEPC_HOTK_FILE "eeepc"
+#define EEEPC_HOTK_CLASS "hotkey"
+#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
+#define EEEPC_HOTK_HID "ASUS010"
+
+#define EEEPC_LOG EEEPC_HOTK_FILE ": "
+#define EEEPC_ERR KERN_ERR EEEPC_LOG
+#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
+#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
+#define EEEPC_INFO KERN_INFO EEEPC_LOG
+
+/*
+ * Definitions for Asus EeePC
+ */
+#define NOTIFY_WLAN_ON 0x10
+#define NOTIFY_BRN_MIN 0x20
+#define NOTIFY_BRN_MAX 0x2f
+
+enum {
+ DISABLE_ASL_WLAN = 0x0001,
+ DISABLE_ASL_BLUETOOTH = 0x0002,
+ DISABLE_ASL_IRDA = 0x0004,
+ DISABLE_ASL_CAMERA = 0x0008,
+ DISABLE_ASL_TV = 0x0010,
+ DISABLE_ASL_GPS = 0x0020,
+ DISABLE_ASL_DISPLAYSWITCH = 0x0040,
+ DISABLE_ASL_MODEM = 0x0080,
+ DISABLE_ASL_CARDREADER = 0x0100
+};
+
+enum {
+ CM_ASL_WLAN = 0,
+ CM_ASL_BLUETOOTH,
+ CM_ASL_IRDA,
+ CM_ASL_1394,
+ CM_ASL_CAMERA,
+ CM_ASL_TV,
+ CM_ASL_GPS,
+ CM_ASL_DVDROM,
+ CM_ASL_DISPLAYSWITCH,
+ CM_ASL_PANELBRIGHT,
+ CM_ASL_BIOSFLASH,
+ CM_ASL_ACPIFLASH,
+ CM_ASL_CPUFV,
+ CM_ASL_CPUTEMPERATURE,
+ CM_ASL_FANCPU,
+ CM_ASL_FANCHASSIS,
+ CM_ASL_USBPORT1,
+ CM_ASL_USBPORT2,
+ CM_ASL_USBPORT3,
+ CM_ASL_MODEM,
+ CM_ASL_CARDREADER,
+ CM_ASL_LID
+};
+
+const char *cm_getv[] = {
+ "WLDG", NULL, NULL, NULL,
+ "CAMG", NULL, NULL, NULL,
+ NULL, "PBLG", NULL, NULL,
+ "CFVG", NULL, NULL, NULL,
+ "USBG", NULL, NULL, "MODG",
+ "CRDG", "LIDG"
+};
+
+const char *cm_setv[] = {
+ "WLDS", NULL, NULL, NULL,
+ "CAMS", NULL, NULL, NULL,
+ "SDSP", "PBLS", "HDPS", NULL,
+ "CFVS", NULL, NULL, NULL,
+ "USBG", NULL, NULL, "MODS",
+ "CRDS", NULL
+};
+
+#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
+
+#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
+#define EEEPC_EC_SC02 0x63
+#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
+#define EEEPC_EC_SFB3 0xD3
+
+/*
+ * This is the main structure, we can use it to store useful information
+ * about the hotk device
+ */
+struct eeepc_hotk {
+ struct acpi_device *device; /* the device we are in */
+ acpi_handle handle; /* the handle of the hotk device */
+ u32 cm_supported; /* the control methods supported
+ by this BIOS */
+ uint init_flag; /* Init flags */
+ u16 event_count[128]; /* count for each event */
+};
+
+/* The actual device the driver binds to */
+static struct eeepc_hotk *ehotk;
+
+/* Platform device/driver */
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = EEEPC_HOTK_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *platform_device;
+
+/*
+ * The hotkey driver declaration
+ */
+static int eeepc_hotk_add(struct acpi_device *device);
+static int eeepc_hotk_remove(struct acpi_device *device, int type);
+
+static const struct acpi_device_id eeepc_device_ids[] = {
+ {EEEPC_HOTK_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
+
+static struct acpi_driver eeepc_hotk_driver = {
+ .name = EEEPC_HOTK_NAME,
+ .class = EEEPC_HOTK_CLASS,
+ .ids = eeepc_device_ids,
+ .ops = {
+ .add = eeepc_hotk_add,
+ .remove = eeepc_hotk_remove,
+ },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *eeepc_backlight_device;
+
+/* The hwmon device */
+static struct device *eeepc_hwmon_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 eeepcbl_ops = {
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+};
+
+MODULE_AUTHOR("Corentin Chary, Eric Cooper");
+MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+/*
+ * ACPI Helpers
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+ 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 ? 0 : -1);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ ulong result;
+
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
+ if (ACPI_FAILURE(status)) {
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
+ }
+}
+
+static int set_acpi(int cm, int value)
+{
+ if (ehotk->cm_supported & (0x1 << cm)) {
+ const char *method = cm_setv[cm];
+ if (method == NULL)
+ return -ENODEV;
+ if (write_acpi_int(ehotk->handle, method, value, NULL))
+ printk(EEEPC_WARNING "Error writing %s\n", method);
+ }
+ return 0;
+}
+
+static int get_acpi(int cm)
+{
+ int value = -1;
+ if ((ehotk->cm_supported & (0x1 << cm))) {
+ const char *method = cm_getv[cm];
+ if (method == NULL)
+ return -ENODEV;
+ if (read_acpi_int(ehotk->handle, method, &value))
+ printk(EEEPC_WARNING "Error reading %s\n", method);
+ }
+ return value;
+}
+
+/*
+ * Backlight
+ */
+static int read_brightness(struct backlight_device *bd)
+{
+ return get_acpi(CM_ASL_PANELBRIGHT);
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+ value = max(0, min(15, value));
+ return set_acpi(CM_ASL_PANELBRIGHT, value);
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ return set_brightness(bd, bd->props.brightness);
+}
+
+/*
+ * Sys helpers
+ */
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_acpi(cm, value);
+ return rv;
+}
+
+static ssize_t show_sys_acpi(int cm, char *buf)
+{
+ return sprintf(buf, "%d\n", get_acpi(cm));
+}
+
+#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_acpi(_cm, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_acpi(_cm, buf, count); \
+ } \
+ static struct device_attribute dev_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644 }, \
+ .show = show_##_name, \
+ .store = store_##_name, \
+ }
+
+EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
+EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
+EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
+EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
+
+static struct attribute *platform_attributes[] = {
+ &dev_attr_camera.attr,
+ &dev_attr_cardr.attr,
+ &dev_attr_disp.attr,
+ &dev_attr_wlan.attr,
+ NULL
+};
+
+static struct attribute_group platform_attribute_group = {
+ .attrs = platform_attributes
+};
+
+/*
+ * Hotkey functions
+ */
+static int eeepc_hotk_check(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ int result;
+
+ result = acpi_bus_get_status(ehotk->device);
+ if (result)
+ return result;
+ if (ehotk->device->status.present) {
+ if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
+ &buffer)) {
+ printk(EEEPC_ERR "Hotkey initialization failed\n");
+ return -ENODEV;
+ } else {
+ printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
+ ehotk->init_flag);
+ }
+ /* get control methods supported */
+ if (read_acpi_int(ehotk->handle, "CMSG"
+ , &ehotk->cm_supported)) {
+ printk(EEEPC_ERR
+ "Get control methods supported failed\n");
+ return -ENODEV;
+ } else {
+ printk(EEEPC_INFO
+ "Get control methods supported: 0x%x\n",
+ ehotk->cm_supported);
+ }
+ } else {
+ printk(EEEPC_ERR "Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void notify_wlan(u32 *event)
+{
+ /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
+ will always be 0x10 */
+ if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
+ const char *method = cm_getv[CM_ASL_WLAN];
+ int value;
+ if (read_acpi_int(ehotk->handle, method, &value))
+ printk(EEEPC_WARNING "Error reading %s\n",
+ method);
+ else if (value == 1)
+ *event = 0x11;
+ }
+}
+
+static void notify_brn(void)
+{
+ struct backlight_device *bd = eeepc_backlight_device;
+ bd->props.brightness = read_brightness(bd);
+}
+
+static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ if (!ehotk)
+ return;
+ if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
+ notify_wlan(&event);
+ if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
+ notify_brn();
+ acpi_bus_generate_proc_event(ehotk->device, event,
+ ehotk->event_count[event % 128]++);
+}
+
+static int eeepc_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+ printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
+ ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
+ if (!ehotk)
+ return -ENOMEM;
+ ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
+ ehotk->handle = device->handle;
+ strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
+ acpi_driver_data(device) = ehotk;
+ ehotk->device = device;
+ result = eeepc_hotk_check();
+ if (result)
+ goto end;
+ status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+ eeepc_hotk_notify, ehotk);
+ if (ACPI_FAILURE(status))
+ printk(EEEPC_ERR "Error installing notify handler\n");
+ end:
+ if (result) {
+ kfree(ehotk);
+ ehotk = NULL;
+ }
+ return result;
+}
+
+static int eeepc_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(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+ eeepc_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(EEEPC_ERR "Error removing notify handler\n");
+ kfree(ehotk);
+ return 0;
+}
+
+/*
+ * Hwmon
+ */
+static int eeepc_get_fan_pwm(void)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
+ return (value);
+}
+
+static void eeepc_set_fan_pwm(int value)
+{
+ value = SENSORS_LIMIT(value, 0, 100);
+ ec_write(EEEPC_EC_SC02, value);
+}
+
+static int eeepc_get_fan_rpm(void)
+{
+ int high = 0;
+ int low = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
+ read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
+ return (high << 8 | low);
+}
+
+static int eeepc_get_fan_ctrl(void)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
+ return ((value & 0x02 ? 1 : 0));
+}
+
+static void eeepc_set_fan_ctrl(int manual)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
+ if (manual)
+ value |= 0x02;
+ else
+ value &= ~0x02;
+ ec_write(EEEPC_EC_SFB3, value);
+}
+
+static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set(value);
+ return rv;
+}
+
+static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
+{
+ return sprintf(buf, "%d\n", get());
+}
+
+#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_hwmon(_set, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_hwmon(_get, buf, count); \
+ } \
+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
+
+EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
+EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+ eeepc_get_fan_pwm, eeepc_set_fan_pwm);
+EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+ eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_fan1_pwm.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group hwmon_attribute_group = {
+ .attrs = hwmon_attributes
+};
+
+/*
+ * exit/init
+ */
+static void eeepc_backlight_exit(void)
+{
+ if (eeepc_backlight_device)
+ backlight_device_unregister(eeepc_backlight_device);
+ eeepc_backlight_device = NULL;
+}
+
+static void eeepc_hwmon_exit(void)
+{
+ struct device *hwmon;
+
+ hwmon = eeepc_hwmon_device;
+ if (!hwmon)
+ return ;
+ hwmon_device_unregister(hwmon);
+ sysfs_remove_group(&hwmon->kobj,
+ &hwmon_attribute_group);
+ eeepc_hwmon_device = NULL;
+}
+
+static void __exit eeepc_laptop_exit(void)
+{
+ eeepc_backlight_exit();
+ eeepc_hwmon_exit();
+ acpi_bus_unregister_driver(&eeepc_hotk_driver);
+ sysfs_remove_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
+ platform_device_unregister(platform_device);
+ platform_driver_unregister(&platform_driver);
+}
+
+static int eeepc_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
+ NULL, &eeepcbl_ops);
+ if (IS_ERR(bd)) {
+ printk(EEEPC_ERR
+ "Could not register eeepc backlight device\n");
+ eeepc_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+ eeepc_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 eeepc_hwmon_init(struct device *dev)
+{
+ struct device *hwmon;
+ int result;
+
+ hwmon = hwmon_device_register(dev);
+ if (IS_ERR(hwmon)) {
+ printk(EEEPC_ERR
+ "Could not register eeepc hwmon device\n");
+ eeepc_hwmon_device = NULL;
+ return PTR_ERR(hwmon);
+ }
+ eeepc_hwmon_device = hwmon;
+ result = sysfs_create_group(&hwmon->kobj,
+ &hwmon_attribute_group);
+ if (result)
+ eeepc_hwmon_exit();
+ return result;
+}
+
+static int __init eeepc_laptop_init(void)
+{
+ struct device *dev;
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+ result = acpi_bus_register_driver(&eeepc_hotk_driver);
+ if (result < 0)
+ return result;
+ if (!ehotk) {
+ acpi_bus_unregister_driver(&eeepc_hotk_driver);
+ return -ENODEV;
+ }
+ dev = acpi_get_physical_device(ehotk->device->handle);
+ result = eeepc_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+ result = eeepc_hwmon_init(dev);
+ if (result)
+ goto fail_hwmon;
+ /* Register platform stuff */
+ result = platform_driver_register(&platform_driver);
+ if (result)
+ goto fail_platform_driver;
+ platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
+ if (!platform_device) {
+ result = -ENOMEM;
+ goto fail_platform_device1;
+ }
+ result = platform_device_add(platform_device);
+ if (result)
+ goto fail_platform_device2;
+ result = sysfs_create_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
+ if (result)
+ goto fail_sysfs;
+ return 0;
+fail_sysfs:
+ platform_device_del(platform_device);
+fail_platform_device2:
+ platform_device_put(platform_device);
+fail_platform_device1:
+ platform_driver_unregister(&platform_driver);
+fail_platform_driver:
+ eeepc_hwmon_exit();
+fail_hwmon:
+ eeepc_backlight_exit();
+fail_backlight:
+ return result;
+}
+
+module_init(eeepc_laptop_init);
+module_exit(eeepc_laptop_exit);
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 302e92418bbe..ff51ab67231c 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -210,13 +210,10 @@ static int hdpu_cpustate_probe(struct platform_device *pdev)
return ret;
}
- proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root);
+ proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate);
if (!proc_de) {
printk(KERN_WARNING "sky_cpustate: "
"Unable to create proc entry\n");
- } else {
- proc_de->proc_fops = &proc_cpustate;
- proc_de->owner = THIS_MODULE;
}
printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 2fa36f7a6eb3..08e26beefe64 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -102,22 +102,17 @@ static int hdpu_nexus_probe(struct platform_device *pdev)
printk(KERN_ERR "sky_nexus: Could not map slot id\n");
}
- hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
+ hdpu_slot_id = proc_create("sky_slot_id", 0666, NULL, &proc_slot_id);
if (!hdpu_slot_id) {
printk(KERN_WARNING "sky_nexus: "
"Unable to create proc dir entry: sky_slot_id\n");
- } else {
- hdpu_slot_id->proc_fops = &proc_slot_id;
- hdpu_slot_id->owner = THIS_MODULE;
}
- hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
- if (!hdpu_chassis_id) {
+ hdpu_chassis_id = proc_create("sky_chassis_id", 0666, NULL,
+ &proc_chassis_id);
+ if (!hdpu_chassis_id)
printk(KERN_WARNING "sky_nexus: "
"Unable to create proc dir entry: sky_chassis_id\n");
- } else {
- hdpu_chassis_id->proc_fops = &proc_chassis_id;
- hdpu_chassis_id->owner = THIS_MODULE;
}
return 0;
@@ -128,8 +123,8 @@ static int hdpu_nexus_remove(struct platform_device *pdev)
slot_id = -1;
chassis_id = -1;
- remove_proc_entry("sky_slot_id", &proc_root);
- remove_proc_entry("sky_chassis_id", &proc_root);
+ remove_proc_entry("sky_slot_id", NULL);
+ remove_proc_entry("sky_chassis_id", NULL);
hdpu_slot_id = 0;
hdpu_chassis_id = 0;
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index 1a0e7978226a..276d3fb68094 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -96,7 +96,7 @@ static inline void do_exec_command(struct service_processor *sp)
{
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
if (ibmasm_send_i2o_message(sp)) {
sp->current_command->status = IBMASM_CMD_FAILED;
@@ -119,7 +119,7 @@ void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
unsigned long flags;
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
spin_lock_irqsave(&sp->lock, flags);
@@ -139,7 +139,7 @@ static void exec_next_command(struct service_processor *sp)
unsigned long flags;
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
spin_lock_irqsave(&sp->lock, flags);
sp->current_command = dequeue_command(sp);
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c
index 3036e785b3e4..1bc4306572a4 100644
--- a/drivers/misc/ibmasm/heartbeat.c
+++ b/drivers/misc/ibmasm/heartbeat.c
@@ -75,9 +75,9 @@ void ibmasm_heartbeat_exit(struct service_processor *sp)
{
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL);
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
suspend_heartbeats = 1;
command_put(sp->heartbeat);
}
@@ -88,7 +88,7 @@ void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size
struct dot_command_header *header = (struct dot_command_header *)cmd->buffer;
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
if (suspend_heartbeats)
return;
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 0c0bb3093e07..80a136352408 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -175,19 +175,17 @@ static int intel_menlow_memory_add(struct acpi_device *device)
goto end;
}
- if (cdev) {
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj, "thermal_cooling");
- if (result)
- goto unregister;
-
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj, "device");
- if (result) {
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- goto unregister;
- }
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj, "thermal_cooling");
+ if (result)
+ goto unregister;
+
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj, "device");
+ if (result) {
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ goto unregister;
}
end:
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 05172d2613d6..6f76573e7c8a 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -75,7 +75,7 @@ ioc4_register_submodule(struct ioc4_submodule *is)
printk(KERN_WARNING
"%s: IOC4 submodule %s probe failed "
"for pci_dev %s",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -102,7 +102,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is)
printk(KERN_WARNING
"%s: IOC4 submodule %s remove failed "
"for pci_dev %s.\n",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -282,7 +282,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
if ((ret = pci_enable_device(pdev))) {
printk(KERN_WARNING
"%s: Failed to enable IOC4 device for pci_dev %s.\n",
- __FUNCTION__, pci_name(pdev));
+ __func__, pci_name(pdev));
goto out;
}
pci_set_master(pdev);
@@ -292,7 +292,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
if (!idd) {
printk(KERN_WARNING
"%s: Failed to allocate IOC4 data for pci_dev %s.\n",
- __FUNCTION__, pci_name(pdev));
+ __func__, pci_name(pdev));
ret = -ENODEV;
goto out_idd;
}
@@ -307,7 +307,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
printk(KERN_WARNING
"%s: Unable to find IOC4 misc resource "
"for pci_dev %s.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
ret = -ENODEV;
goto out_pci;
}
@@ -316,7 +316,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
printk(KERN_WARNING
"%s: Unable to request IOC4 misc region "
"for pci_dev %s.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
ret = -ENODEV;
goto out_pci;
}
@@ -326,7 +326,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
printk(KERN_WARNING
"%s: Unable to remap IOC4 misc region "
"for pci_dev %s.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
ret = -ENODEV;
goto out_misc_region;
}
@@ -372,7 +372,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
printk(KERN_WARNING
"%s: IOC4 submodule 0x%s probe failed "
"for pci_dev %s.\n",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -406,7 +406,7 @@ ioc4_remove(struct pci_dev *pdev)
printk(KERN_WARNING
"%s: IOC4 submodule 0x%s remove failed "
"for pci_dev %s.\n",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -418,7 +418,7 @@ ioc4_remove(struct pci_dev *pdev)
printk(KERN_WARNING
"%s: Unable to get IOC4 misc mapping for pci_dev %s. "
"Device removal may be incomplete.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
}
release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 6d6286c4eeac..fa394104339c 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -47,6 +47,7 @@
* to test the HW NMI watchdog
* F## = Break at do_fork for ## iterations
* S## = Break at sys_open for ## iterations
+ * I## = Run the single step test ## iterations
*
* NOTE: that the do_fork and sys_open tests are mutually exclusive.
*
@@ -132,7 +133,7 @@ static int send_ack;
static int final_ack;
static int hw_break_val;
static int hw_break_val2;
-#if defined(CONFIG_ARM) || defined(CONFIG_MIPS)
+#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
static int arch_needs_sstep_emulation = 1;
#else
static int arch_needs_sstep_emulation;
@@ -375,7 +376,7 @@ static void emul_sstep_get(char *arg)
break;
case 1:
/* set breakpoint */
- break_helper("Z0", 0, sstep_addr);
+ break_helper("Z0", NULL, sstep_addr);
break;
case 2:
/* Continue */
@@ -383,7 +384,7 @@ static void emul_sstep_get(char *arg)
break;
case 3:
/* Clear breakpoint */
- break_helper("z0", 0, sstep_addr);
+ break_helper("z0", NULL, sstep_addr);
break;
default:
eprintk("kgdbts: ERROR failed sstep get emulation\n");
@@ -465,11 +466,11 @@ static struct test_struct sw_breakpoint_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -499,14 +500,14 @@ static struct test_struct singlestep_break_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs }, /* Write registers */
{ "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
- { "g", "kgdbts_break_test", 0, check_single_step },
+ { "g", "kgdbts_break_test", NULL, check_single_step },
{ "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs }, /* Write registers */
{ "D", "OK" }, /* Remove all breakpoints and continues */
{ "", "" },
@@ -520,14 +521,14 @@ static struct test_struct do_fork_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "do_fork", 0, check_and_rewind_pc }, /* check location */
+ { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
{ "write", "OK", write_regs }, /* Write registers */
{ "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
- { "g", "do_fork", 0, check_single_step },
+ { "g", "do_fork", NULL, check_single_step },
{ "do_fork", "OK", sw_break, }, /* set sw breakpoint */
{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
- { "D", "OK", 0, final_ack_set }, /* detach and unregister I/O */
+ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
{ "", "" },
};
@@ -538,14 +539,14 @@ static struct test_struct sys_open_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "sys_open", 0, check_and_rewind_pc }, /* check location */
+ { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
{ "write", "OK", write_regs }, /* Write registers */
{ "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
{ "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
- { "g", "sys_open", 0, check_single_step },
+ { "g", "sys_open", NULL, check_single_step },
{ "sys_open", "OK", sw_break, }, /* set sw breakpoint */
{ "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
- { "D", "OK", 0, final_ack_set }, /* detach and unregister I/O */
+ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
{ "", "" },
};
@@ -556,11 +557,11 @@ static struct test_struct hw_breakpoint_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */
{ "c", "T0*", }, /* Continue */
- { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -570,12 +571,12 @@ static struct test_struct hw_breakpoint_test[] = {
static struct test_struct hw_write_break_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */
- { "c", "T0*", 0, got_break }, /* Continue */
- { "g", "silent", 0, check_and_rewind_pc },
+ { "c", "T0*", NULL, got_break }, /* Continue */
+ { "g", "silent", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -585,12 +586,12 @@ static struct test_struct hw_write_break_test[] = {
static struct test_struct hw_access_break_test[] = {
{ "?", "S0*" }, /* Clear break points */
{ "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */
- { "c", "T0*", 0, got_break }, /* Continue */
- { "g", "silent", 0, check_and_rewind_pc },
+ { "c", "T0*", NULL, got_break }, /* Continue */
+ { "g", "silent", NULL, check_and_rewind_pc },
{ "write", "OK", write_regs },
{ "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -599,9 +600,9 @@ static struct test_struct hw_access_break_test[] = {
*/
static struct test_struct nmi_sleep_test[] = {
{ "?", "S0*" }, /* Clear break points */
- { "c", "T0*", 0, got_break }, /* Continue */
+ { "c", "T0*", NULL, got_break }, /* Continue */
{ "D", "OK" }, /* Detach */
- { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "D", "OK", NULL, got_break }, /* On success we made it here */
{ "", "" },
};
@@ -874,18 +875,23 @@ static void kgdbts_run_tests(void)
{
char *ptr;
int fork_test = 0;
- int sys_open_test = 0;
+ int do_sys_open_test = 0;
+ int sstep_test = 1000;
int nmi_sleep = 0;
+ int i;
ptr = strstr(config, "F");
if (ptr)
- fork_test = simple_strtol(ptr+1, NULL, 10);
+ fork_test = simple_strtol(ptr + 1, NULL, 10);
ptr = strstr(config, "S");
if (ptr)
- sys_open_test = simple_strtol(ptr+1, NULL, 10);
+ do_sys_open_test = simple_strtol(ptr + 1, NULL, 10);
ptr = strstr(config, "N");
if (ptr)
nmi_sleep = simple_strtol(ptr+1, NULL, 10);
+ ptr = strstr(config, "I");
+ if (ptr)
+ sstep_test = simple_strtol(ptr+1, NULL, 10);
/* required internal KGDB tests */
v1printk("kgdbts:RUN plant and detach test\n");
@@ -894,8 +900,13 @@ static void kgdbts_run_tests(void)
run_breakpoint_test(0);
v1printk("kgdbts:RUN bad memory access test\n");
run_bad_read_test();
- v1printk("kgdbts:RUN singlestep breakpoint test\n");
- run_singlestep_break_test();
+ v1printk("kgdbts:RUN singlestep test %i iterations\n", sstep_test);
+ for (i = 0; i < sstep_test; i++) {
+ run_singlestep_break_test();
+ if (i % 100 == 0)
+ v1printk("kgdbts:RUN singlestep [%i/%i]\n",
+ i, sstep_test);
+ }
/* ===Optional tests=== */
@@ -922,7 +933,7 @@ static void kgdbts_run_tests(void)
repeat_test = fork_test;
printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints\n",
repeat_test);
- kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+ kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
run_do_fork_test();
return;
}
@@ -931,11 +942,11 @@ static void kgdbts_run_tests(void)
* executed because a kernel thread will be spawned at the very
* end to unregister the debug hooks.
*/
- if (sys_open_test) {
- repeat_test = sys_open_test;
+ if (do_sys_open_test) {
+ repeat_test = do_sys_open_test;
printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints\n",
repeat_test);
- kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+ kthread_run(kgdbts_unreg_thread, NULL, "kgdbts_unreg");
run_sys_open_test();
return;
}
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 7fa61e907e1c..71d1c84e2fa8 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -12,6 +12,7 @@
* or alternatively, you might use OpenHaptics provided by Sensable.
*/
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -91,11 +92,8 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
unsigned long flags;
unsigned int i;
- if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
- _IOC_NR(cmd) > PH_IOC_MAXNR)
- return -ENOTTY;
-
switch (cmd) {
+ case PHN_SETREG:
case PHN_SET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
@@ -126,6 +124,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
phantom_status(dev, dev->status & ~PHB_RUNNING);
spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
+ case PHN_SETREGS:
case PHN_SET_REGS:
if (copy_from_user(&rs, argp, sizeof(rs)))
return -EFAULT;
@@ -143,6 +142,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
}
spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
+ case PHN_GETREG:
case PHN_GET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
@@ -155,6 +155,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
break;
+ case PHN_GETREGS:
case PHN_GET_REGS: {
u32 m;
@@ -168,6 +169,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
for (i = 0; i < m; i++)
if (rs.mask & BIT(i))
rs.values[i] = ioread32(dev->iaddr + i);
+ atomic_set(&dev->counter, 0);
spin_unlock_irqrestore(&dev->regs_lock, flags);
if (copy_to_user(argp, &rs, sizeof(rs)))
@@ -191,6 +193,20 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
return 0;
}
+#ifdef CONFIG_COMPAT
+static long phantom_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
+ cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT);
+ cmd |= sizeof(void *) << _IOC_SIZESHIFT;
+ }
+ return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define phantom_compat_ioctl NULL
+#endif
+
static int phantom_open(struct inode *inode, struct file *file)
{
struct phantom_device *dev = container_of(inode->i_cdev,
@@ -239,11 +255,12 @@ static unsigned int phantom_poll(struct file *file, poll_table *wait)
pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
poll_wait(file, &dev->wait, wait);
- if (atomic_read(&dev->counter)) {
+
+ if (!(dev->status & PHB_RUNNING))
+ mask = POLLERR;
+ else if (atomic_read(&dev->counter))
mask = POLLIN | POLLRDNORM;
- atomic_dec(&dev->counter);
- } else if ((dev->status & PHB_RUNNING) == 0)
- mask = POLLIN | POLLRDNORM | POLLERR;
+
pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
return mask;
@@ -253,6 +270,7 @@ static struct file_operations phantom_file_ops = {
.open = phantom_open,
.release = phantom_release,
.unlocked_ioctl = phantom_ioctl,
+ .compat_ioctl = phantom_compat_ioctl,
.poll = phantom_poll,
};
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index 5515234be86a..03a87a307e32 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -157,215 +157,136 @@ struct xpc_msg {
/*
* Define the return values and values passed to user's callout functions.
* (It is important to add new value codes at the end just preceding
- * xpcUnknownReason, which must have the highest numerical value.)
+ * xpUnknownReason, which must have the highest numerical value.)
*/
-enum xpc_retval {
- xpcSuccess = 0,
+enum xp_retval {
+ xpSuccess = 0,
- xpcNotConnected, /* 1: channel is not connected */
- xpcConnected, /* 2: channel connected (opened) */
- xpcRETIRED1, /* 3: (formerly xpcDisconnected) */
+ xpNotConnected, /* 1: channel is not connected */
+ xpConnected, /* 2: channel connected (opened) */
+ xpRETIRED1, /* 3: (formerly xpDisconnected) */
- xpcMsgReceived, /* 4: message received */
- xpcMsgDelivered, /* 5: message delivered and acknowledged */
+ xpMsgReceived, /* 4: message received */
+ xpMsgDelivered, /* 5: message delivered and acknowledged */
- xpcRETIRED2, /* 6: (formerly xpcTransferFailed) */
+ xpRETIRED2, /* 6: (formerly xpTransferFailed) */
- xpcNoWait, /* 7: operation would require wait */
- xpcRetry, /* 8: retry operation */
- xpcTimeout, /* 9: timeout in xpc_allocate_msg_wait() */
- xpcInterrupted, /* 10: interrupted wait */
+ xpNoWait, /* 7: operation would require wait */
+ xpRetry, /* 8: retry operation */
+ xpTimeout, /* 9: timeout in xpc_allocate_msg_wait() */
+ xpInterrupted, /* 10: interrupted wait */
- xpcUnequalMsgSizes, /* 11: message size disparity between sides */
- xpcInvalidAddress, /* 12: invalid address */
+ xpUnequalMsgSizes, /* 11: message size disparity between sides */
+ xpInvalidAddress, /* 12: invalid address */
- xpcNoMemory, /* 13: no memory available for XPC structures */
- xpcLackOfResources, /* 14: insufficient resources for operation */
- xpcUnregistered, /* 15: channel is not registered */
- xpcAlreadyRegistered, /* 16: channel is already registered */
+ xpNoMemory, /* 13: no memory available for XPC structures */
+ xpLackOfResources, /* 14: insufficient resources for operation */
+ xpUnregistered, /* 15: channel is not registered */
+ xpAlreadyRegistered, /* 16: channel is already registered */
- xpcPartitionDown, /* 17: remote partition is down */
- xpcNotLoaded, /* 18: XPC module is not loaded */
- xpcUnloading, /* 19: this side is unloading XPC module */
+ xpPartitionDown, /* 17: remote partition is down */
+ xpNotLoaded, /* 18: XPC module is not loaded */
+ xpUnloading, /* 19: this side is unloading XPC module */
- xpcBadMagic, /* 20: XPC MAGIC string not found */
+ xpBadMagic, /* 20: XPC MAGIC string not found */
- xpcReactivating, /* 21: remote partition was reactivated */
+ xpReactivating, /* 21: remote partition was reactivated */
- xpcUnregistering, /* 22: this side is unregistering channel */
- xpcOtherUnregistering, /* 23: other side is unregistering channel */
+ xpUnregistering, /* 22: this side is unregistering channel */
+ xpOtherUnregistering, /* 23: other side is unregistering channel */
- xpcCloneKThread, /* 24: cloning kernel thread */
- xpcCloneKThreadFailed, /* 25: cloning kernel thread failed */
+ xpCloneKThread, /* 24: cloning kernel thread */
+ xpCloneKThreadFailed, /* 25: cloning kernel thread failed */
- xpcNoHeartbeat, /* 26: remote partition has no heartbeat */
+ xpNoHeartbeat, /* 26: remote partition has no heartbeat */
- xpcPioReadError, /* 27: PIO read error */
- xpcPhysAddrRegFailed, /* 28: registration of phys addr range failed */
+ xpPioReadError, /* 27: PIO read error */
+ xpPhysAddrRegFailed, /* 28: registration of phys addr range failed */
- xpcBteDirectoryError, /* 29: maps to BTEFAIL_DIR */
- xpcBtePoisonError, /* 30: maps to BTEFAIL_POISON */
- xpcBteWriteError, /* 31: maps to BTEFAIL_WERR */
- xpcBteAccessError, /* 32: maps to BTEFAIL_ACCESS */
- xpcBtePWriteError, /* 33: maps to BTEFAIL_PWERR */
- xpcBtePReadError, /* 34: maps to BTEFAIL_PRERR */
- xpcBteTimeOutError, /* 35: maps to BTEFAIL_TOUT */
- xpcBteXtalkError, /* 36: maps to BTEFAIL_XTERR */
- xpcBteNotAvailable, /* 37: maps to BTEFAIL_NOTAVAIL */
- xpcBteUnmappedError, /* 38: unmapped BTEFAIL_ error */
+ xpRETIRED3, /* 29: (formerly xpBteDirectoryError) */
+ xpRETIRED4, /* 30: (formerly xpBtePoisonError) */
+ xpRETIRED5, /* 31: (formerly xpBteWriteError) */
+ xpRETIRED6, /* 32: (formerly xpBteAccessError) */
+ xpRETIRED7, /* 33: (formerly xpBtePWriteError) */
+ xpRETIRED8, /* 34: (formerly xpBtePReadError) */
+ xpRETIRED9, /* 35: (formerly xpBteTimeOutError) */
+ xpRETIRED10, /* 36: (formerly xpBteXtalkError) */
+ xpRETIRED11, /* 37: (formerly xpBteNotAvailable) */
+ xpRETIRED12, /* 38: (formerly xpBteUnmappedError) */
- xpcBadVersion, /* 39: bad version number */
- xpcVarsNotSet, /* 40: the XPC variables are not set up */
- xpcNoRsvdPageAddr, /* 41: unable to get rsvd page's phys addr */
- xpcInvalidPartid, /* 42: invalid partition ID */
- xpcLocalPartid, /* 43: local partition ID */
+ xpBadVersion, /* 39: bad version number */
+ xpVarsNotSet, /* 40: the XPC variables are not set up */
+ xpNoRsvdPageAddr, /* 41: unable to get rsvd page's phys addr */
+ xpInvalidPartid, /* 42: invalid partition ID */
+ xpLocalPartid, /* 43: local partition ID */
- xpcOtherGoingDown, /* 44: other side going down, reason unknown */
- xpcSystemGoingDown, /* 45: system is going down, reason unknown */
- xpcSystemHalt, /* 46: system is being halted */
- xpcSystemReboot, /* 47: system is being rebooted */
- xpcSystemPoweroff, /* 48: system is being powered off */
+ xpOtherGoingDown, /* 44: other side going down, reason unknown */
+ xpSystemGoingDown, /* 45: system is going down, reason unknown */
+ xpSystemHalt, /* 46: system is being halted */
+ xpSystemReboot, /* 47: system is being rebooted */
+ xpSystemPoweroff, /* 48: system is being powered off */
- xpcDisconnecting, /* 49: channel disconnecting (closing) */
+ xpDisconnecting, /* 49: channel disconnecting (closing) */
- xpcOpenCloseError, /* 50: channel open/close protocol error */
+ xpOpenCloseError, /* 50: channel open/close protocol error */
- xpcDisconnected, /* 51: channel disconnected (closed) */
+ xpDisconnected, /* 51: channel disconnected (closed) */
- xpcBteSh2Start, /* 52: BTE CRB timeout */
+ xpBteCopyError, /* 52: bte_copy() returned error */
- /* 53: 0x1 BTE Error Response Short */
- xpcBteSh2RspShort = xpcBteSh2Start + BTEFAIL_SH2_RESP_SHORT,
-
- /* 54: 0x2 BTE Error Response Long */
- xpcBteSh2RspLong = xpcBteSh2Start + BTEFAIL_SH2_RESP_LONG,
-
- /* 56: 0x4 BTE Error Response DSB */
- xpcBteSh2RspDSB = xpcBteSh2Start + BTEFAIL_SH2_RESP_DSP,
-
- /* 60: 0x8 BTE Error Response Access */
- xpcBteSh2RspAccess = xpcBteSh2Start + BTEFAIL_SH2_RESP_ACCESS,
-
- /* 68: 0x10 BTE Error CRB timeout */
- xpcBteSh2CRBTO = xpcBteSh2Start + BTEFAIL_SH2_CRB_TO,
-
- /* 84: 0x20 BTE Error NACK limit */
- xpcBteSh2NACKLimit = xpcBteSh2Start + BTEFAIL_SH2_NACK_LIMIT,
-
- /* 115: BTE end */
- xpcBteSh2End = xpcBteSh2Start + BTEFAIL_SH2_ALL,
-
- xpcUnknownReason /* 116: unknown reason - must be last in enum */
+ xpUnknownReason /* 53: unknown reason - must be last in enum */
};
/*
- * Define the callout function types used by XPC to update the user on
- * connection activity and state changes (via the user function registered by
- * xpc_connect()) and to notify them of messages received and delivered (via
- * the user function registered by xpc_send_notify()).
- *
- * The two function types are xpc_channel_func and xpc_notify_func and
- * both share the following arguments, with the exception of "data", which
- * only xpc_channel_func has.
+ * Define the callout function type used by XPC to update the user on
+ * connection activity and state changes via the user function registered
+ * by xpc_connect().
*
* Arguments:
*
- * reason - reason code. (See following table.)
+ * reason - reason code.
* partid - partition ID associated with condition.
* ch_number - channel # associated with condition.
- * data - pointer to optional data. (See following table.)
+ * data - pointer to optional data.
* key - pointer to optional user-defined value provided as the "key"
- * argument to xpc_connect() or xpc_send_notify().
+ * argument to xpc_connect().
*
- * In the following table the "Optional Data" column applies to callouts made
- * to functions registered by xpc_connect(). A "NA" in that column indicates
- * that this reason code can be passed to functions registered by
- * xpc_send_notify() (i.e. they don't have data arguments).
+ * A reason code of xpConnected indicates that a connection has been
+ * established to the specified partition on the specified channel. The data
+ * argument indicates the max number of entries allowed in the message queue.
*
- * Also, the first three reason codes in the following table indicate
- * success, whereas the others indicate failure. When a failure reason code
- * is received, one can assume that the channel is not connected.
+ * A reason code of xpMsgReceived indicates that a XPC message arrived from
+ * the specified partition on the specified channel. The data argument
+ * specifies the address of the message's payload. The user must call
+ * xpc_received() when finished with the payload.
*
- *
- * Reason Code | Cause | Optional Data
- * =====================+================================+=====================
- * xpcConnected | connection has been established| max #of entries
- * | to the specified partition on | allowed in message
- * | the specified channel | queue
- * ---------------------+--------------------------------+---------------------
- * xpcMsgReceived | an XPC message arrived from | address of payload
- * | the specified partition on the |
- * | specified channel | [the user must call
- * | | xpc_received() when
- * | | finished with the
- * | | payload]
- * ---------------------+--------------------------------+---------------------
- * xpcMsgDelivered | notification that the message | NA
- * | was delivered to the intended |
- * | recipient and that they have |
- * | acknowledged its receipt by |
- * | calling xpc_received() |
- * =====================+================================+=====================
- * xpcUnequalMsgSizes | can't connect to the specified | NULL
- * | partition on the specified |
- * | channel because of mismatched |
- * | message sizes |
- * ---------------------+--------------------------------+---------------------
- * xpcNoMemory | insufficient memory avaiable | NULL
- * | to allocate message queue |
- * ---------------------+--------------------------------+---------------------
- * xpcLackOfResources | lack of resources to create | NULL
- * | the necessary kthreads to |
- * | support the channel |
- * ---------------------+--------------------------------+---------------------
- * xpcUnregistering | this side's user has | NULL or NA
- * | unregistered by calling |
- * | xpc_disconnect() |
- * ---------------------+--------------------------------+---------------------
- * xpcOtherUnregistering| the other side's user has | NULL or NA
- * | unregistered by calling |
- * | xpc_disconnect() |
- * ---------------------+--------------------------------+---------------------
- * xpcNoHeartbeat | the other side's XPC is no | NULL or NA
- * | longer heartbeating |
- * | |
- * ---------------------+--------------------------------+---------------------
- * xpcUnloading | this side's XPC module is | NULL or NA
- * | being unloaded |
- * | |
- * ---------------------+--------------------------------+---------------------
- * xpcOtherUnloading | the other side's XPC module is | NULL or NA
- * | is being unloaded |
- * | |
- * ---------------------+--------------------------------+---------------------
- * xpcPioReadError | xp_nofault_PIOR() returned an | NULL or NA
- * | error while sending an IPI |
- * | |
- * ---------------------+--------------------------------+---------------------
- * xpcInvalidAddress | the address either received or | NULL or NA
- * | sent by the specified partition|
- * | is invalid |
- * ---------------------+--------------------------------+---------------------
- * xpcBteNotAvailable | attempt to pull data from the | NULL or NA
- * xpcBtePoisonError | specified partition over the |
- * xpcBteWriteError | specified channel via a |
- * xpcBteAccessError | bte_copy() failed |
- * xpcBteTimeOutError | |
- * xpcBteXtalkError | |
- * xpcBteDirectoryError | |
- * xpcBteGenericError | |
- * xpcBteUnmappedError | |
- * ---------------------+--------------------------------+---------------------
- * xpcUnknownReason | the specified channel to the | NULL or NA
- * | specified partition was |
- * | unavailable for unknown reasons|
- * =====================+================================+=====================
+ * All other reason codes indicate failure. The data argmument is NULL.
+ * When a failure reason code is received, one can assume that the channel
+ * is not connected.
*/
-
-typedef void (*xpc_channel_func) (enum xpc_retval reason, partid_t partid,
+typedef void (*xpc_channel_func) (enum xp_retval reason, short partid,
int ch_number, void *data, void *key);
-typedef void (*xpc_notify_func) (enum xpc_retval reason, partid_t partid,
+/*
+ * Define the callout function type used by XPC to notify the user of
+ * messages received and delivered via the user function registered by
+ * xpc_send_notify().
+ *
+ * Arguments:
+ *
+ * reason - reason code.
+ * partid - partition ID associated with condition.
+ * ch_number - channel # associated with condition.
+ * key - pointer to optional user-defined value provided as the "key"
+ * argument to xpc_send_notify().
+ *
+ * A reason code of xpMsgDelivered indicates that the message was delivered
+ * to the intended recipient and that they have acknowledged its receipt by
+ * calling xpc_received().
+ *
+ * All other reason codes indicate failure.
+ */
+typedef void (*xpc_notify_func) (enum xp_retval reason, short partid,
int ch_number, void *key);
/*
@@ -401,57 +322,57 @@ struct xpc_registration {
struct xpc_interface {
void (*connect) (int);
void (*disconnect) (int);
- enum xpc_retval (*allocate) (partid_t, int, u32, void **);
- enum xpc_retval (*send) (partid_t, int, void *);
- enum xpc_retval (*send_notify) (partid_t, int, void *,
+ enum xp_retval (*allocate) (short, int, u32, void **);
+ enum xp_retval (*send) (short, int, void *);
+ enum xp_retval (*send_notify) (short, int, void *,
xpc_notify_func, void *);
- void (*received) (partid_t, int, void *);
- enum xpc_retval (*partid_to_nasids) (partid_t, void *);
+ void (*received) (short, int, void *);
+ enum xp_retval (*partid_to_nasids) (short, void *);
};
extern struct xpc_interface xpc_interface;
extern void xpc_set_interface(void (*)(int),
void (*)(int),
- enum xpc_retval (*)(partid_t, int, u32, void **),
- enum xpc_retval (*)(partid_t, int, void *),
- enum xpc_retval (*)(partid_t, int, void *,
+ enum xp_retval (*)(short, int, u32, void **),
+ enum xp_retval (*)(short, int, void *),
+ enum xp_retval (*)(short, int, void *,
xpc_notify_func, void *),
- void (*)(partid_t, int, void *),
- enum xpc_retval (*)(partid_t, void *));
+ void (*)(short, int, void *),
+ enum xp_retval (*)(short, void *));
extern void xpc_clear_interface(void);
-extern enum xpc_retval xpc_connect(int, xpc_channel_func, void *, u16,
+extern enum xp_retval xpc_connect(int, xpc_channel_func, void *, u16,
u16, u32, u32);
extern void xpc_disconnect(int);
-static inline enum xpc_retval
-xpc_allocate(partid_t partid, int ch_number, u32 flags, void **payload)
+static inline enum xp_retval
+xpc_allocate(short partid, int ch_number, u32 flags, void **payload)
{
return xpc_interface.allocate(partid, ch_number, flags, payload);
}
-static inline enum xpc_retval
-xpc_send(partid_t partid, int ch_number, void *payload)
+static inline enum xp_retval
+xpc_send(short partid, int ch_number, void *payload)
{
return xpc_interface.send(partid, ch_number, payload);
}
-static inline enum xpc_retval
-xpc_send_notify(partid_t partid, int ch_number, void *payload,
+static inline enum xp_retval
+xpc_send_notify(short partid, int ch_number, void *payload,
xpc_notify_func func, void *key)
{
return xpc_interface.send_notify(partid, ch_number, payload, func, key);
}
static inline void
-xpc_received(partid_t partid, int ch_number, void *payload)
+xpc_received(short partid, int ch_number, void *payload)
{
return xpc_interface.received(partid, ch_number, payload);
}
-static inline enum xpc_retval
-xpc_partid_to_nasids(partid_t partid, void *nasids)
+static inline enum xp_retval
+xpc_partid_to_nasids(short partid, void *nasids)
{
return xpc_interface.partid_to_nasids(partid, nasids);
}
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c
index 1fbf99bae963..196480b691a1 100644
--- a/drivers/misc/sgi-xp/xp_main.c
+++ b/drivers/misc/sgi-xp/xp_main.c
@@ -42,21 +42,21 @@ EXPORT_SYMBOL_GPL(xpc_registrations);
/*
* Initialize the XPC interface to indicate that XPC isn't loaded.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_notloaded(void)
{
- return xpcNotLoaded;
+ return xpNotLoaded;
}
struct xpc_interface xpc_interface = {
(void (*)(int))xpc_notloaded,
(void (*)(int))xpc_notloaded,
- (enum xpc_retval(*)(partid_t, int, u32, void **))xpc_notloaded,
- (enum xpc_retval(*)(partid_t, int, void *))xpc_notloaded,
- (enum xpc_retval(*)(partid_t, int, void *, xpc_notify_func, void *))
+ (enum xp_retval(*)(short, int, u32, void **))xpc_notloaded,
+ (enum xp_retval(*)(short, int, void *))xpc_notloaded,
+ (enum xp_retval(*)(short, int, void *, xpc_notify_func, void *))
xpc_notloaded,
- (void (*)(partid_t, int, void *))xpc_notloaded,
- (enum xpc_retval(*)(partid_t, void *))xpc_notloaded
+ (void (*)(short, int, void *))xpc_notloaded,
+ (enum xp_retval(*)(short, void *))xpc_notloaded
};
EXPORT_SYMBOL_GPL(xpc_interface);
@@ -66,12 +66,12 @@ EXPORT_SYMBOL_GPL(xpc_interface);
void
xpc_set_interface(void (*connect) (int),
void (*disconnect) (int),
- enum xpc_retval (*allocate) (partid_t, int, u32, void **),
- enum xpc_retval (*send) (partid_t, int, void *),
- enum xpc_retval (*send_notify) (partid_t, int, void *,
+ enum xp_retval (*allocate) (short, int, u32, void **),
+ enum xp_retval (*send) (short, int, void *),
+ enum xp_retval (*send_notify) (short, int, void *,
xpc_notify_func, void *),
- void (*received) (partid_t, int, void *),
- enum xpc_retval (*partid_to_nasids) (partid_t, void *))
+ void (*received) (short, int, void *),
+ enum xp_retval (*partid_to_nasids) (short, void *))
{
xpc_interface.connect = connect;
xpc_interface.disconnect = disconnect;
@@ -91,16 +91,16 @@ xpc_clear_interface(void)
{
xpc_interface.connect = (void (*)(int))xpc_notloaded;
xpc_interface.disconnect = (void (*)(int))xpc_notloaded;
- xpc_interface.allocate = (enum xpc_retval(*)(partid_t, int, u32,
+ xpc_interface.allocate = (enum xp_retval(*)(short, int, u32,
void **))xpc_notloaded;
- xpc_interface.send = (enum xpc_retval(*)(partid_t, int, void *))
+ xpc_interface.send = (enum xp_retval(*)(short, int, void *))
xpc_notloaded;
- xpc_interface.send_notify = (enum xpc_retval(*)(partid_t, int, void *,
+ xpc_interface.send_notify = (enum xp_retval(*)(short, int, void *,
xpc_notify_func,
void *))xpc_notloaded;
- xpc_interface.received = (void (*)(partid_t, int, void *))
+ xpc_interface.received = (void (*)(short, int, void *))
xpc_notloaded;
- xpc_interface.partid_to_nasids = (enum xpc_retval(*)(partid_t, void *))
+ xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *))
xpc_notloaded;
}
EXPORT_SYMBOL_GPL(xpc_clear_interface);
@@ -123,13 +123,13 @@ EXPORT_SYMBOL_GPL(xpc_clear_interface);
* nentries - max #of XPC message entries a message queue can contain.
* The actual number, which is determined when a connection
* is established and may be less then requested, will be
- * passed to the user via the xpcConnected callout.
+ * passed to the user via the xpConnected callout.
* assigned_limit - max number of kthreads allowed to be processing
* messages (per connection) at any given instant.
* idle_limit - max number of kthreads allowed to be idle at any given
* instant.
*/
-enum xpc_retval
+enum xp_retval
xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
u16 nentries, u32 assigned_limit, u32 idle_limit)
{
@@ -143,12 +143,12 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
registration = &xpc_registrations[ch_number];
if (mutex_lock_interruptible(&registration->mutex) != 0)
- return xpcInterrupted;
+ return xpInterrupted;
/* if XPC_CHANNEL_REGISTERED(ch_number) */
if (registration->func != NULL) {
mutex_unlock(&registration->mutex);
- return xpcAlreadyRegistered;
+ return xpAlreadyRegistered;
}
/* register the channel for connection */
@@ -163,7 +163,7 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
xpc_interface.connect(ch_number);
- return xpcSuccess;
+ return xpSuccess;
}
EXPORT_SYMBOL_GPL(xpc_connect);
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h
index 9eb6d4a3269c..11ac267ed68f 100644
--- a/drivers/misc/sgi-xp/xpc.h
+++ b/drivers/misc/sgi-xp/xpc.h
@@ -172,13 +172,13 @@ struct xpc_vars {
(_version >= _XPC_VERSION(3, 1))
static inline int
-xpc_hb_allowed(partid_t partid, struct xpc_vars *vars)
+xpc_hb_allowed(short partid, struct xpc_vars *vars)
{
return ((vars->heartbeating_to_mask & (1UL << partid)) != 0);
}
static inline void
-xpc_allow_hb(partid_t partid, struct xpc_vars *vars)
+xpc_allow_hb(short partid, struct xpc_vars *vars)
{
u64 old_mask, new_mask;
@@ -190,7 +190,7 @@ xpc_allow_hb(partid_t partid, struct xpc_vars *vars)
}
static inline void
-xpc_disallow_hb(partid_t partid, struct xpc_vars *vars)
+xpc_disallow_hb(short partid, struct xpc_vars *vars)
{
u64 old_mask, new_mask;
@@ -408,11 +408,11 @@ struct xpc_notify {
* messages.
*/
struct xpc_channel {
- partid_t partid; /* ID of remote partition connected */
+ short partid; /* ID of remote partition connected */
spinlock_t lock; /* lock for updating this structure */
u32 flags; /* general flags */
- enum xpc_retval reason; /* reason why channel is disconnect'g */
+ enum xp_retval reason; /* reason why channel is disconnect'g */
int reason_line; /* line# disconnect initiated from */
u16 number; /* channel # */
@@ -522,7 +522,7 @@ struct xpc_partition {
spinlock_t act_lock; /* protect updating of act_state */
u8 act_state; /* from XPC HB viewpoint */
u8 remote_vars_version; /* version# of partition's vars */
- enum xpc_retval reason; /* reason partition is deactivating */
+ enum xp_retval reason; /* reason partition is deactivating */
int reason_line; /* line# deactivation initiated from */
int reactivate_nasid; /* nasid in partition to reactivate */
@@ -615,7 +615,7 @@ struct xpc_partition {
/* interval in seconds to print 'waiting disengagement' messages */
#define XPC_DISENGAGE_PRINTMSG_INTERVAL 10
-#define XPC_PARTID(_p) ((partid_t) ((_p) - &xpc_partitions[0]))
+#define XPC_PARTID(_p) ((short)((_p) - &xpc_partitions[0]))
/* found in xp_main.c */
extern struct xpc_registration xpc_registrations[];
@@ -646,31 +646,31 @@ extern void xpc_allow_IPI_ops(void);
extern void xpc_restrict_IPI_ops(void);
extern int xpc_identify_act_IRQ_sender(void);
extern int xpc_partition_disengaged(struct xpc_partition *);
-extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *);
+extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *);
extern void xpc_mark_partition_inactive(struct xpc_partition *);
extern void xpc_discovery(void);
extern void xpc_check_remote_hb(void);
extern void xpc_deactivate_partition(const int, struct xpc_partition *,
- enum xpc_retval);
-extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *);
+ enum xp_retval);
+extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *);
/* found in xpc_channel.c */
extern void xpc_initiate_connect(int);
extern void xpc_initiate_disconnect(int);
-extern enum xpc_retval xpc_initiate_allocate(partid_t, int, u32, void **);
-extern enum xpc_retval xpc_initiate_send(partid_t, int, void *);
-extern enum xpc_retval xpc_initiate_send_notify(partid_t, int, void *,
- xpc_notify_func, void *);
-extern void xpc_initiate_received(partid_t, int, void *);
-extern enum xpc_retval xpc_setup_infrastructure(struct xpc_partition *);
-extern enum xpc_retval xpc_pull_remote_vars_part(struct xpc_partition *);
+extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **);
+extern enum xp_retval xpc_initiate_send(short, int, void *);
+extern enum xp_retval xpc_initiate_send_notify(short, int, void *,
+ xpc_notify_func, void *);
+extern void xpc_initiate_received(short, int, void *);
+extern enum xp_retval xpc_setup_infrastructure(struct xpc_partition *);
+extern enum xp_retval xpc_pull_remote_vars_part(struct xpc_partition *);
extern void xpc_process_channel_activity(struct xpc_partition *);
extern void xpc_connected_callout(struct xpc_channel *);
extern void xpc_deliver_msg(struct xpc_channel *);
extern void xpc_disconnect_channel(const int, struct xpc_channel *,
- enum xpc_retval, unsigned long *);
-extern void xpc_disconnect_callout(struct xpc_channel *, enum xpc_retval);
-extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval);
+ enum xp_retval, unsigned long *);
+extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval);
+extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval);
extern void xpc_teardown_infrastructure(struct xpc_partition *);
static inline void
@@ -901,7 +901,7 @@ xpc_IPI_receive(AMO_t *amo)
return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR);
}
-static inline enum xpc_retval
+static inline enum xp_retval
xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
{
int ret = 0;
@@ -923,7 +923,7 @@ xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
local_irq_restore(irq_flags);
- return ((ret == 0) ? xpcSuccess : xpcPioReadError);
+ return ((ret == 0) ? xpSuccess : xpPioReadError);
}
/*
@@ -992,7 +992,7 @@ xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string,
unsigned long *irq_flags)
{
struct xpc_partition *part = &xpc_partitions[ch->partid];
- enum xpc_retval ret;
+ enum xp_retval ret;
if (likely(part->act_state != XPC_P_DEACTIVATING)) {
ret = xpc_IPI_send(part->remote_IPI_amo_va,
@@ -1001,7 +1001,7 @@ xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string,
part->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY);
dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
ipi_flag_string, ch->partid, ch->number, ret);
- if (unlikely(ret != xpcSuccess)) {
+ if (unlikely(ret != xpSuccess)) {
if (irq_flags != NULL)
spin_unlock_irqrestore(&ch->lock, *irq_flags);
XPC_DEACTIVATE_PARTITION(part, ret);
@@ -1123,41 +1123,10 @@ xpc_IPI_init(int index)
return amo;
}
-static inline enum xpc_retval
+static inline enum xp_retval
xpc_map_bte_errors(bte_result_t error)
{
- if (error == BTE_SUCCESS)
- return xpcSuccess;
-
- if (is_shub2()) {
- if (BTE_VALID_SH2_ERROR(error))
- return xpcBteSh2Start + error;
- return xpcBteUnmappedError;
- }
- switch (error) {
- case BTE_SUCCESS:
- return xpcSuccess;
- case BTEFAIL_DIR:
- return xpcBteDirectoryError;
- case BTEFAIL_POISON:
- return xpcBtePoisonError;
- case BTEFAIL_WERR:
- return xpcBteWriteError;
- case BTEFAIL_ACCESS:
- return xpcBteAccessError;
- case BTEFAIL_PWERR:
- return xpcBtePWriteError;
- case BTEFAIL_PRERR:
- return xpcBtePReadError;
- case BTEFAIL_TOUT:
- return xpcBteTimeOutError;
- case BTEFAIL_XTERR:
- return xpcBteXtalkError;
- case BTEFAIL_NOTAVAIL:
- return xpcBteNotAvailable;
- default:
- return xpcBteUnmappedError;
- }
+ return ((error == BTE_SUCCESS) ? xpSuccess : xpBteCopyError);
}
/*
diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c
index bfcb9ea968e9..9c90c2d55c08 100644
--- a/drivers/misc/sgi-xp/xpc_channel.c
+++ b/drivers/misc/sgi-xp/xpc_channel.c
@@ -53,7 +53,7 @@ xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
* Set up the initial values for the XPartition Communication channels.
*/
static void
-xpc_initialize_channels(struct xpc_partition *part, partid_t partid)
+xpc_initialize_channels(struct xpc_partition *part, short partid)
{
int ch_number;
struct xpc_channel *ch;
@@ -90,12 +90,12 @@ xpc_initialize_channels(struct xpc_partition *part, partid_t partid)
* Setup the infrastructure necessary to support XPartition Communication
* between the specified remote partition and the local one.
*/
-enum xpc_retval
+enum xp_retval
xpc_setup_infrastructure(struct xpc_partition *part)
{
int ret, cpuid;
struct timer_list *timer;
- partid_t partid = XPC_PARTID(part);
+ short partid = XPC_PARTID(part);
/*
* Zero out MOST of the entry for this partition. Only the fields
@@ -114,7 +114,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
GFP_KERNEL);
if (part->channels == NULL) {
dev_err(xpc_chan, "can't get memory for channels\n");
- return xpcNoMemory;
+ return xpNoMemory;
}
part->nchannels = XPC_NCHANNELS;
@@ -129,7 +129,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
part->channels = NULL;
dev_err(xpc_chan, "can't get memory for local get/put "
"values\n");
- return xpcNoMemory;
+ return xpNoMemory;
}
part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE,
@@ -143,7 +143,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
part->local_GPs = NULL;
kfree(part->channels);
part->channels = NULL;
- return xpcNoMemory;
+ return xpNoMemory;
}
/* allocate all the required open and close args */
@@ -159,7 +159,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
part->local_GPs = NULL;
kfree(part->channels);
part->channels = NULL;
- return xpcNoMemory;
+ return xpNoMemory;
}
part->remote_openclose_args =
@@ -175,7 +175,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
part->local_GPs = NULL;
kfree(part->channels);
part->channels = NULL;
- return xpcNoMemory;
+ return xpNoMemory;
}
xpc_initialize_channels(part, partid);
@@ -209,7 +209,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
part->local_GPs = NULL;
kfree(part->channels);
part->channels = NULL;
- return xpcLackOfResources;
+ return xpLackOfResources;
}
/* Setup a timer to check for dropped IPIs */
@@ -243,7 +243,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
xpc_vars_part[partid].nchannels = part->nchannels;
xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -254,7 +254,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
* dst must be a cacheline aligned virtual address on this partition.
* cnt must be an cacheline sized
*/
-static enum xpc_retval
+static enum xp_retval
xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst,
const void *src, size_t cnt)
{
@@ -270,7 +270,7 @@ xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst,
bte_ret = xp_bte_copy((u64)src, (u64)dst, (u64)cnt,
(BTE_NORMAL | BTE_WACQUIRE), NULL);
if (bte_ret == BTE_SUCCESS)
- return xpcSuccess;
+ return xpSuccess;
dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n",
XPC_PARTID(part), bte_ret);
@@ -282,7 +282,7 @@ xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst,
* Pull the remote per partition specific variables from the specified
* partition.
*/
-enum xpc_retval
+enum xp_retval
xpc_pull_remote_vars_part(struct xpc_partition *part)
{
u8 buffer[L1_CACHE_BYTES * 2];
@@ -290,8 +290,8 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
(struct xpc_vars_part *)L1_CACHE_ALIGN((u64)buffer);
struct xpc_vars_part *pulled_entry;
u64 remote_entry_cacheline_pa, remote_entry_pa;
- partid_t partid = XPC_PARTID(part);
- enum xpc_retval ret;
+ short partid = XPC_PARTID(part);
+ enum xp_retval ret;
/* pull the cacheline that contains the variables we're interested in */
@@ -311,7 +311,7 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline,
(void *)remote_entry_cacheline_pa,
L1_CACHE_BYTES);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_dbg(xpc_chan, "failed to pull XPC vars_part from "
"partition %d, ret=%d\n", partid, ret);
return ret;
@@ -326,11 +326,11 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
dev_dbg(xpc_chan, "partition %d's XPC vars_part for "
"partition %d has bad magic value (=0x%lx)\n",
partid, sn_partition_id, pulled_entry->magic);
- return xpcBadMagic;
+ return xpBadMagic;
}
/* they've not been initialized yet */
- return xpcRetry;
+ return xpRetry;
}
if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) {
@@ -344,7 +344,7 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
dev_err(xpc_chan, "partition %d's XPC vars_part for "
"partition %d are not valid\n", partid,
sn_partition_id);
- return xpcInvalidAddress;
+ return xpInvalidAddress;
}
/* the variables we imported look to be valid */
@@ -366,9 +366,9 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
}
if (pulled_entry->magic == XPC_VP_MAGIC1)
- return xpcRetry;
+ return xpRetry;
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -379,7 +379,7 @@ xpc_get_IPI_flags(struct xpc_partition *part)
{
unsigned long irq_flags;
u64 IPI_amo;
- enum xpc_retval ret;
+ enum xp_retval ret;
/*
* See if there are any IPI flags to be handled.
@@ -398,7 +398,7 @@ xpc_get_IPI_flags(struct xpc_partition *part)
(void *)part->
remote_openclose_args_pa,
XPC_OPENCLOSE_ARGS_SIZE);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
XPC_DEACTIVATE_PARTITION(part, ret);
dev_dbg(xpc_chan, "failed to pull openclose args from "
@@ -414,7 +414,7 @@ xpc_get_IPI_flags(struct xpc_partition *part)
ret = xpc_pull_remote_cachelines(part, part->remote_GPs,
(void *)part->remote_GPs_pa,
XPC_GP_SIZE);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
XPC_DEACTIVATE_PARTITION(part, ret);
dev_dbg(xpc_chan, "failed to pull GPs from partition "
@@ -431,7 +431,7 @@ xpc_get_IPI_flags(struct xpc_partition *part)
/*
* Allocate the local message queue and the notify queue.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_allocate_local_msgqueue(struct xpc_channel *ch)
{
unsigned long irq_flags;
@@ -464,18 +464,18 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch)
ch->local_nentries = nentries;
}
spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpcSuccess;
+ return xpSuccess;
}
dev_dbg(xpc_chan, "can't get memory for local message queue and notify "
"queue, partid=%d, channel=%d\n", ch->partid, ch->number);
- return xpcNoMemory;
+ return xpNoMemory;
}
/*
* Allocate the cached remote message queue.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_allocate_remote_msgqueue(struct xpc_channel *ch)
{
unsigned long irq_flags;
@@ -502,12 +502,12 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch)
ch->remote_nentries = nentries;
}
spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpcSuccess;
+ return xpSuccess;
}
dev_dbg(xpc_chan, "can't get memory for cached remote message queue, "
"partid=%d, channel=%d\n", ch->partid, ch->number);
- return xpcNoMemory;
+ return xpNoMemory;
}
/*
@@ -515,20 +515,20 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch)
*
* Note: Assumes all of the channel sizes are filled in.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_allocate_msgqueues(struct xpc_channel *ch)
{
unsigned long irq_flags;
- enum xpc_retval ret;
+ enum xp_retval ret;
DBUG_ON(ch->flags & XPC_C_SETUP);
ret = xpc_allocate_local_msgqueue(ch);
- if (ret != xpcSuccess)
+ if (ret != xpSuccess)
return ret;
ret = xpc_allocate_remote_msgqueue(ch);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
kfree(ch->local_msgqueue_base);
ch->local_msgqueue = NULL;
kfree(ch->notify_queue);
@@ -540,7 +540,7 @@ xpc_allocate_msgqueues(struct xpc_channel *ch)
ch->flags |= XPC_C_SETUP;
spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -552,7 +552,7 @@ xpc_allocate_msgqueues(struct xpc_channel *ch)
static void
xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
{
- enum xpc_retval ret;
+ enum xp_retval ret;
DBUG_ON(!spin_is_locked(&ch->lock));
@@ -568,7 +568,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
ret = xpc_allocate_msgqueues(ch);
spin_lock_irqsave(&ch->lock, *irq_flags);
- if (ret != xpcSuccess)
+ if (ret != xpSuccess)
XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags);
if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING))
@@ -603,7 +603,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
* Notify those who wanted to be notified upon delivery of their message.
*/
static void
-xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put)
+xpc_notify_senders(struct xpc_channel *ch, enum xp_retval reason, s64 put)
{
struct xpc_notify *notify;
u8 notify_type;
@@ -748,7 +748,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
if (ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE) {
spin_unlock_irqrestore(&ch->lock, *irq_flags);
- xpc_disconnect_callout(ch, xpcDisconnected);
+ xpc_disconnect_callout(ch, xpDisconnected);
spin_lock_irqsave(&ch->lock, *irq_flags);
}
@@ -791,7 +791,7 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number,
struct xpc_openclose_args *args =
&part->remote_openclose_args[ch_number];
struct xpc_channel *ch = &part->channels[ch_number];
- enum xpc_retval reason;
+ enum xp_retval reason;
spin_lock_irqsave(&ch->lock, irq_flags);
@@ -871,10 +871,10 @@ again:
if (!(ch->flags & XPC_C_DISCONNECTING)) {
reason = args->reason;
- if (reason <= xpcSuccess || reason > xpcUnknownReason)
- reason = xpcUnknownReason;
- else if (reason == xpcUnregistering)
- reason = xpcOtherUnregistering;
+ if (reason <= xpSuccess || reason > xpUnknownReason)
+ reason = xpUnknownReason;
+ else if (reason == xpUnregistering)
+ reason = xpOtherUnregistering;
XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);
@@ -961,7 +961,7 @@ again:
if (ch->flags & XPC_C_OPENREQUEST) {
if (args->msg_size != ch->msg_size) {
- XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes,
+ XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
&irq_flags);
spin_unlock_irqrestore(&ch->lock, irq_flags);
return;
@@ -991,7 +991,7 @@ again:
return;
}
if (!(ch->flags & XPC_C_OPENREQUEST)) {
- XPC_DISCONNECT_CHANNEL(ch, xpcOpenCloseError,
+ XPC_DISCONNECT_CHANNEL(ch, xpOpenCloseError,
&irq_flags);
spin_unlock_irqrestore(&ch->lock, irq_flags);
return;
@@ -1042,18 +1042,18 @@ again:
/*
* Attempt to establish a channel connection to a remote partition.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_connect_channel(struct xpc_channel *ch)
{
unsigned long irq_flags;
struct xpc_registration *registration = &xpc_registrations[ch->number];
if (mutex_trylock(&registration->mutex) == 0)
- return xpcRetry;
+ return xpRetry;
if (!XPC_CHANNEL_REGISTERED(ch->number)) {
mutex_unlock(&registration->mutex);
- return xpcUnregistered;
+ return xpUnregistered;
}
spin_lock_irqsave(&ch->lock, irq_flags);
@@ -1095,10 +1095,10 @@ xpc_connect_channel(struct xpc_channel *ch)
* the channel lock as needed.
*/
mutex_unlock(&registration->mutex);
- XPC_DISCONNECT_CHANNEL(ch, xpcUnequalMsgSizes,
+ XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes,
&irq_flags);
spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpcUnequalMsgSizes;
+ return xpUnequalMsgSizes;
}
} else {
ch->msg_size = registration->msg_size;
@@ -1120,7 +1120,7 @@ xpc_connect_channel(struct xpc_channel *ch)
spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -1203,7 +1203,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number)
* Notify senders that messages sent have been
* received and delivered by the other side.
*/
- xpc_notify_senders(ch, xpcMsgDelivered,
+ xpc_notify_senders(ch, xpMsgDelivered,
ch->remote_GP.get);
}
@@ -1335,7 +1335,7 @@ xpc_process_channel_activity(struct xpc_partition *part)
* at the same time.
*/
void
-xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason)
+xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason)
{
unsigned long irq_flags;
int ch_number;
@@ -1375,7 +1375,7 @@ xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason)
void
xpc_teardown_infrastructure(struct xpc_partition *part)
{
- partid_t partid = XPC_PARTID(part);
+ short partid = XPC_PARTID(part);
/*
* We start off by making this partition inaccessible to local
@@ -1428,7 +1428,7 @@ xpc_teardown_infrastructure(struct xpc_partition *part)
void
xpc_initiate_connect(int ch_number)
{
- partid_t partid;
+ short partid;
struct xpc_partition *part;
struct xpc_channel *ch;
@@ -1456,13 +1456,13 @@ xpc_connected_callout(struct xpc_channel *ch)
/* let the registerer know that a connection has been established */
if (ch->func != NULL) {
- dev_dbg(xpc_chan, "ch->func() called, reason=xpcConnected, "
+ dev_dbg(xpc_chan, "ch->func() called, reason=xpConnected, "
"partid=%d, channel=%d\n", ch->partid, ch->number);
- ch->func(xpcConnected, ch->partid, ch->number,
+ ch->func(xpConnected, ch->partid, ch->number,
(void *)(u64)ch->local_nentries, ch->key);
- dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, "
+ dev_dbg(xpc_chan, "ch->func() returned, reason=xpConnected, "
"partid=%d, channel=%d\n", ch->partid, ch->number);
}
}
@@ -1484,7 +1484,7 @@ void
xpc_initiate_disconnect(int ch_number)
{
unsigned long irq_flags;
- partid_t partid;
+ short partid;
struct xpc_partition *part;
struct xpc_channel *ch;
@@ -1503,7 +1503,7 @@ xpc_initiate_disconnect(int ch_number)
if (!(ch->flags & XPC_C_DISCONNECTED)) {
ch->flags |= XPC_C_WDISCONNECT;
- XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering,
+ XPC_DISCONNECT_CHANNEL(ch, xpUnregistering,
&irq_flags);
}
@@ -1528,7 +1528,7 @@ xpc_initiate_disconnect(int ch_number)
*/
void
xpc_disconnect_channel(const int line, struct xpc_channel *ch,
- enum xpc_retval reason, unsigned long *irq_flags)
+ enum xp_retval reason, unsigned long *irq_flags)
{
u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED);
@@ -1563,7 +1563,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
} else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
!(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
- /* start a kthread that will do the xpcDisconnecting callout */
+ /* start a kthread that will do the xpDisconnecting callout */
xpc_create_kthreads(ch, 1, 1);
}
@@ -1575,7 +1575,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
}
void
-xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason)
+xpc_disconnect_callout(struct xpc_channel *ch, enum xp_retval reason)
{
/*
* Let the channel's registerer know that the channel is being
@@ -1598,13 +1598,13 @@ xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason)
* Wait for a message entry to become available for the specified channel,
* but don't wait any longer than 1 jiffy.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_allocate_msg_wait(struct xpc_channel *ch)
{
- enum xpc_retval ret;
+ enum xp_retval ret;
if (ch->flags & XPC_C_DISCONNECTING) {
- DBUG_ON(ch->reason == xpcInterrupted);
+ DBUG_ON(ch->reason == xpInterrupted);
return ch->reason;
}
@@ -1614,11 +1614,11 @@ xpc_allocate_msg_wait(struct xpc_channel *ch)
if (ch->flags & XPC_C_DISCONNECTING) {
ret = ch->reason;
- DBUG_ON(ch->reason == xpcInterrupted);
+ DBUG_ON(ch->reason == xpInterrupted);
} else if (ret == 0) {
- ret = xpcTimeout;
+ ret = xpTimeout;
} else {
- ret = xpcInterrupted;
+ ret = xpInterrupted;
}
return ret;
@@ -1628,12 +1628,12 @@ xpc_allocate_msg_wait(struct xpc_channel *ch)
* Allocate an entry for a message from the message queue associated with the
* specified channel.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
struct xpc_msg **address_of_msg)
{
struct xpc_msg *msg;
- enum xpc_retval ret;
+ enum xp_retval ret;
s64 put;
/* this reference will be dropped in xpc_send_msg() */
@@ -1645,7 +1645,7 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
}
if (!(ch->flags & XPC_C_CONNECTED)) {
xpc_msgqueue_deref(ch);
- return xpcNotConnected;
+ return xpNotConnected;
}
/*
@@ -1653,7 +1653,7 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
* If none are available, we'll make sure that we grab the latest
* GP values.
*/
- ret = xpcTimeout;
+ ret = xpTimeout;
while (1) {
@@ -1683,16 +1683,16 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
* that will cause the IPI handler to fetch the latest
* GP values as if an IPI was sent by the other side.
*/
- if (ret == xpcTimeout)
+ if (ret == xpTimeout)
xpc_IPI_send_local_msgrequest(ch);
if (flags & XPC_NOWAIT) {
xpc_msgqueue_deref(ch);
- return xpcNoWait;
+ return xpNoWait;
}
ret = xpc_allocate_msg_wait(ch);
- if (ret != xpcInterrupted && ret != xpcTimeout) {
+ if (ret != xpInterrupted && ret != xpTimeout) {
xpc_msgqueue_deref(ch);
return ret;
}
@@ -1711,7 +1711,7 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
*address_of_msg = msg;
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -1727,11 +1727,11 @@ xpc_allocate_msg(struct xpc_channel *ch, u32 flags,
* payload - address of the allocated payload area pointer (filled in on
* return) in which the user-defined message is constructed.
*/
-enum xpc_retval
-xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload)
+enum xp_retval
+xpc_initiate_allocate(short partid, int ch_number, u32 flags, void **payload)
{
struct xpc_partition *part = &xpc_partitions[partid];
- enum xpc_retval ret = xpcUnknownReason;
+ enum xp_retval ret = xpUnknownReason;
struct xpc_msg *msg = NULL;
DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
@@ -1814,11 +1814,11 @@ xpc_send_msgs(struct xpc_channel *ch, s64 initial_put)
* local message queue's Put value and sends an IPI to the partition the
* message is being sent to.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type,
xpc_notify_func func, void *key)
{
- enum xpc_retval ret = xpcSuccess;
+ enum xp_retval ret = xpSuccess;
struct xpc_notify *notify = notify;
s64 put, msg_number = msg->number;
@@ -1908,12 +1908,12 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type,
* payload - pointer to the payload area allocated via
* xpc_initiate_allocate().
*/
-enum xpc_retval
-xpc_initiate_send(partid_t partid, int ch_number, void *payload)
+enum xp_retval
+xpc_initiate_send(short partid, int ch_number, void *payload)
{
struct xpc_partition *part = &xpc_partitions[partid];
struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
- enum xpc_retval ret;
+ enum xp_retval ret;
dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg,
partid, ch_number);
@@ -1957,13 +1957,13 @@ xpc_initiate_send(partid_t partid, int ch_number, void *payload)
* receipt. THIS FUNCTION MUST BE NON-BLOCKING.
* key - user-defined key to be passed to the function when it's called.
*/
-enum xpc_retval
-xpc_initiate_send_notify(partid_t partid, int ch_number, void *payload,
+enum xp_retval
+xpc_initiate_send_notify(short partid, int ch_number, void *payload,
xpc_notify_func func, void *key)
{
struct xpc_partition *part = &xpc_partitions[partid];
struct xpc_msg *msg = XPC_MSG_ADDRESS(payload);
- enum xpc_retval ret;
+ enum xp_retval ret;
dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg,
partid, ch_number);
@@ -1985,7 +1985,7 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get)
struct xpc_msg *remote_msg, *msg;
u32 msg_index, nmsgs;
u64 msg_offset;
- enum xpc_retval ret;
+ enum xp_retval ret;
if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) {
/* we were interrupted by a signal */
@@ -2012,7 +2012,7 @@ xpc_pull_remote_msg(struct xpc_channel *ch, s64 get)
ret = xpc_pull_remote_cachelines(part, msg, remote_msg,
nmsgs * ch->msg_size);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_dbg(xpc_chan, "failed to pull %d msgs starting with"
" msg %ld from partition %d, channel=%d, "
@@ -2112,7 +2112,7 @@ xpc_deliver_msg(struct xpc_channel *ch)
ch->number);
/* deliver the message to its intended recipient */
- ch->func(xpcMsgReceived, ch->partid, ch->number,
+ ch->func(xpMsgReceived, ch->partid, ch->number,
&msg->payload, ch->key);
dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, "
@@ -2203,7 +2203,7 @@ xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags)
* xpc_initiate_allocate().
*/
void
-xpc_initiate_received(partid_t partid, int ch_number, void *payload)
+xpc_initiate_received(short partid, int ch_number, void *payload)
{
struct xpc_partition *part = &xpc_partitions[partid];
struct xpc_channel *ch;
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index f673ba90eb0e..08256ed0d9a6 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -315,13 +315,13 @@ xpc_initiate_discovery(void *ignore)
* the XPC per partition variables from the remote partition and waiting for
* the remote partition to pull ours.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_make_first_contact(struct xpc_partition *part)
{
- enum xpc_retval ret;
+ enum xp_retval ret;
- while ((ret = xpc_pull_remote_vars_part(part)) != xpcSuccess) {
- if (ret != xpcRetry) {
+ while ((ret = xpc_pull_remote_vars_part(part)) != xpSuccess) {
+ if (ret != xpRetry) {
XPC_DEACTIVATE_PARTITION(part, ret);
return ret;
}
@@ -406,7 +406,7 @@ xpc_partition_up(struct xpc_partition *part)
dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part));
- if (xpc_setup_infrastructure(part) != xpcSuccess)
+ if (xpc_setup_infrastructure(part) != xpSuccess)
return;
/*
@@ -418,7 +418,7 @@ xpc_partition_up(struct xpc_partition *part)
(void)xpc_part_ref(part); /* this will always succeed */
- if (xpc_make_first_contact(part) == xpcSuccess)
+ if (xpc_make_first_contact(part) == xpSuccess)
xpc_channel_mgr(part);
xpc_part_deref(part);
@@ -429,7 +429,7 @@ xpc_partition_up(struct xpc_partition *part)
static int
xpc_activating(void *__partid)
{
- partid_t partid = (u64)__partid;
+ short partid = (u64)__partid;
struct xpc_partition *part = &xpc_partitions[partid];
unsigned long irq_flags;
@@ -470,7 +470,7 @@ xpc_activating(void *__partid)
spin_lock_irqsave(&part->act_lock, irq_flags);
part->act_state = XPC_P_INACTIVE;
- XPC_SET_REASON(part, xpcPhysAddrRegFailed, __LINE__);
+ XPC_SET_REASON(part, xpPhysAddrRegFailed, __LINE__);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
part->remote_rp_pa = 0;
return 0;
@@ -488,7 +488,7 @@ xpc_activating(void *__partid)
xpc_disallow_hb(partid, xpc_vars);
xpc_mark_partition_inactive(part);
- if (part->reason == xpcReactivating) {
+ if (part->reason == xpReactivating) {
/* interrupting ourselves results in activating partition */
xpc_IPI_send_reactivate(part);
}
@@ -499,7 +499,7 @@ xpc_activating(void *__partid)
void
xpc_activate_partition(struct xpc_partition *part)
{
- partid_t partid = XPC_PARTID(part);
+ short partid = XPC_PARTID(part);
unsigned long irq_flags;
struct task_struct *kthread;
@@ -508,7 +508,7 @@ xpc_activate_partition(struct xpc_partition *part)
DBUG_ON(part->act_state != XPC_P_INACTIVE);
part->act_state = XPC_P_ACTIVATION_REQ;
- XPC_SET_REASON(part, xpcCloneKThread, __LINE__);
+ XPC_SET_REASON(part, xpCloneKThread, __LINE__);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -517,7 +517,7 @@ xpc_activate_partition(struct xpc_partition *part)
if (IS_ERR(kthread)) {
spin_lock_irqsave(&part->act_lock, irq_flags);
part->act_state = XPC_P_INACTIVE;
- XPC_SET_REASON(part, xpcCloneKThreadFailed, __LINE__);
+ XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
}
}
@@ -541,7 +541,7 @@ xpc_activate_partition(struct xpc_partition *part)
irqreturn_t
xpc_notify_IRQ_handler(int irq, void *dev_id)
{
- partid_t partid = (partid_t) (u64)dev_id;
+ short partid = (short)(u64)dev_id;
struct xpc_partition *part = &xpc_partitions[partid];
DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
@@ -643,7 +643,7 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch)
static int
xpc_kthread_start(void *args)
{
- partid_t partid = XPC_UNPACK_ARG1(args);
+ short partid = XPC_UNPACK_ARG1(args);
u16 ch_number = XPC_UNPACK_ARG2(args);
struct xpc_partition *part = &xpc_partitions[partid];
struct xpc_channel *ch;
@@ -696,7 +696,7 @@ xpc_kthread_start(void *args)
ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
spin_unlock_irqrestore(&ch->lock, irq_flags);
- xpc_disconnect_callout(ch, xpcDisconnecting);
+ xpc_disconnect_callout(ch, xpDisconnecting);
spin_lock_irqsave(&ch->lock, irq_flags);
ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
@@ -776,7 +776,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed,
* then we'll deadlock if all other kthreads assigned
* to this channel are blocked in the channel's
* registerer, because the only thing that will unblock
- * them is the xpcDisconnecting callout that this
+ * them is the xpDisconnecting callout that this
* failed kthread_run() would have made.
*/
@@ -796,7 +796,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed,
* to function.
*/
spin_lock_irqsave(&ch->lock, irq_flags);
- XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,
+ XPC_DISCONNECT_CHANNEL(ch, xpLackOfResources,
&irq_flags);
spin_unlock_irqrestore(&ch->lock, irq_flags);
}
@@ -809,7 +809,7 @@ void
xpc_disconnect_wait(int ch_number)
{
unsigned long irq_flags;
- partid_t partid;
+ short partid;
struct xpc_partition *part;
struct xpc_channel *ch;
int wakeup_channel_mgr;
@@ -857,9 +857,9 @@ xpc_disconnect_wait(int ch_number)
}
static void
-xpc_do_exit(enum xpc_retval reason)
+xpc_do_exit(enum xp_retval reason)
{
- partid_t partid;
+ short partid;
int active_part_count, printed_waiting_msg = 0;
struct xpc_partition *part;
unsigned long printmsg_time, disengage_request_timeout = 0;
@@ -955,7 +955,7 @@ xpc_do_exit(enum xpc_retval reason)
del_timer_sync(&xpc_hb_timer);
DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
- if (reason == xpcUnloading) {
+ if (reason == xpUnloading) {
/* take ourselves off of the reboot_notifier_list */
(void)unregister_reboot_notifier(&xpc_reboot_notifier);
@@ -981,20 +981,20 @@ xpc_do_exit(enum xpc_retval reason)
static int
xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
{
- enum xpc_retval reason;
+ enum xp_retval reason;
switch (event) {
case SYS_RESTART:
- reason = xpcSystemReboot;
+ reason = xpSystemReboot;
break;
case SYS_HALT:
- reason = xpcSystemHalt;
+ reason = xpSystemHalt;
break;
case SYS_POWER_OFF:
- reason = xpcSystemPoweroff;
+ reason = xpSystemPoweroff;
break;
default:
- reason = xpcSystemGoingDown;
+ reason = xpSystemGoingDown;
}
xpc_do_exit(reason);
@@ -1008,7 +1008,7 @@ static void
xpc_die_disengage(void)
{
struct xpc_partition *part;
- partid_t partid;
+ short partid;
unsigned long engaged;
long time, printmsg_time, disengage_request_timeout;
@@ -1124,7 +1124,7 @@ int __init
xpc_init(void)
{
int ret;
- partid_t partid;
+ short partid;
struct xpc_partition *part;
struct task_struct *kthread;
size_t buf_size;
@@ -1279,7 +1279,7 @@ xpc_init(void)
/* mark this new thread as a non-starter */
complete(&xpc_discovery_exited);
- xpc_do_exit(xpcUnloading);
+ xpc_do_exit(xpUnloading);
return -EBUSY;
}
@@ -1297,7 +1297,7 @@ module_init(xpc_init);
void __exit
xpc_exit(void)
{
- xpc_do_exit(xpcUnloading);
+ xpc_do_exit(xpUnloading);
}
module_exit(xpc_exit);
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index 27e200ec5826..7dd4b5812c42 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -211,7 +211,7 @@ xpc_rsvd_page_init(void)
*/
amos_page = xpc_vars->amos_page;
if (amos_page == NULL) {
- amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0));
+ amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1));
if (amos_page == NULL) {
dev_err(xpc_part, "can't allocate page of AMOs\n");
return NULL;
@@ -230,7 +230,7 @@ xpc_rsvd_page_init(void)
dev_err(xpc_part, "can't change memory "
"protections\n");
uncached_free_page(__IA64_UNCACHED_OFFSET |
- TO_PHYS((u64)amos_page));
+ TO_PHYS((u64)amos_page), 1);
return NULL;
}
}
@@ -403,7 +403,7 @@ xpc_check_remote_hb(void)
{
struct xpc_vars *remote_vars;
struct xpc_partition *part;
- partid_t partid;
+ short partid;
bte_result_t bres;
remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer;
@@ -444,7 +444,7 @@ xpc_check_remote_hb(void)
(remote_vars->heartbeat_offline == 0)) ||
!xpc_hb_allowed(sn_partition_id, remote_vars)) {
- XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat);
+ XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat);
continue;
}
@@ -459,7 +459,7 @@ xpc_check_remote_hb(void)
* is large enough to contain a copy of their reserved page header and
* part_nasids mask.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa)
{
@@ -469,7 +469,7 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
*remote_rp_pa = xpc_get_rsvd_page_pa(nasid);
if (*remote_rp_pa == 0)
- return xpcNoRsvdPageAddr;
+ return xpNoRsvdPageAddr;
/* pull over the reserved page header and part_nasids mask */
bres = xp_bte_copy(*remote_rp_pa, (u64)remote_rp,
@@ -489,18 +489,18 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
if (remote_rp->partid < 1 ||
remote_rp->partid > (XP_MAX_PARTITIONS - 1)) {
- return xpcInvalidPartid;
+ return xpInvalidPartid;
}
if (remote_rp->partid == sn_partition_id)
- return xpcLocalPartid;
+ return xpLocalPartid;
if (XPC_VERSION_MAJOR(remote_rp->version) !=
XPC_VERSION_MAJOR(XPC_RP_VERSION)) {
- return xpcBadVersion;
+ return xpBadVersion;
}
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -509,13 +509,13 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
* remote_vars points to a buffer that is cacheline aligned for BTE copies and
* assumed to be of size XPC_RP_VARS_SIZE.
*/
-static enum xpc_retval
+static enum xp_retval
xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
{
int bres;
if (remote_vars_pa == 0)
- return xpcVarsNotSet;
+ return xpVarsNotSet;
/* pull over the cross partition variables */
bres = xp_bte_copy(remote_vars_pa, (u64)remote_vars, XPC_RP_VARS_SIZE,
@@ -525,10 +525,10 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
if (XPC_VERSION_MAJOR(remote_vars->version) !=
XPC_VERSION_MAJOR(XPC_V_VERSION)) {
- return xpcBadVersion;
+ return xpBadVersion;
}
- return xpcSuccess;
+ return xpSuccess;
}
/*
@@ -604,16 +604,16 @@ xpc_identify_act_IRQ_req(int nasid)
int reactivate = 0;
int stamp_diff;
struct timespec remote_rp_stamp = { 0, 0 };
- partid_t partid;
+ short partid;
struct xpc_partition *part;
- enum xpc_retval ret;
+ enum xp_retval ret;
/* pull over the reserved page structure */
remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer;
ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_warn(xpc_part, "unable to get reserved page from nasid %d, "
"which sent interrupt, reason=%d\n", nasid, ret);
return;
@@ -632,7 +632,7 @@ xpc_identify_act_IRQ_req(int nasid)
remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer;
ret = xpc_get_remote_vars(remote_vars_pa, remote_vars);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_warn(xpc_part, "unable to get XPC variables from nasid %d, "
"which sent interrupt, reason=%d\n", nasid, ret);
@@ -699,7 +699,7 @@ xpc_identify_act_IRQ_req(int nasid)
&remote_rp_stamp, remote_rp_pa,
remote_vars_pa, remote_vars);
part->reactivate_nasid = nasid;
- XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
+ XPC_DEACTIVATE_PARTITION(part, xpReactivating);
return;
}
@@ -754,11 +754,11 @@ xpc_identify_act_IRQ_req(int nasid)
if (reactivate) {
part->reactivate_nasid = nasid;
- XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
+ XPC_DEACTIVATE_PARTITION(part, xpReactivating);
} else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) &&
xpc_partition_disengage_requested(1UL << partid)) {
- XPC_DEACTIVATE_PARTITION(part, xpcOtherGoingDown);
+ XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown);
}
}
@@ -825,7 +825,7 @@ xpc_identify_act_IRQ_sender(void)
int
xpc_partition_disengaged(struct xpc_partition *part)
{
- partid_t partid = XPC_PARTID(part);
+ short partid = XPC_PARTID(part);
int disengaged;
disengaged = (xpc_partition_engaged(1UL << partid) == 0);
@@ -870,20 +870,20 @@ xpc_partition_disengaged(struct xpc_partition *part)
/*
* Mark specified partition as active.
*/
-enum xpc_retval
+enum xp_retval
xpc_mark_partition_active(struct xpc_partition *part)
{
unsigned long irq_flags;
- enum xpc_retval ret;
+ enum xp_retval ret;
dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part));
spin_lock_irqsave(&part->act_lock, irq_flags);
if (part->act_state == XPC_P_ACTIVATING) {
part->act_state = XPC_P_ACTIVE;
- ret = xpcSuccess;
+ ret = xpSuccess;
} else {
- DBUG_ON(part->reason == xpcSuccess);
+ DBUG_ON(part->reason == xpSuccess);
ret = part->reason;
}
spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -896,7 +896,7 @@ xpc_mark_partition_active(struct xpc_partition *part)
*/
void
xpc_deactivate_partition(const int line, struct xpc_partition *part,
- enum xpc_retval reason)
+ enum xp_retval reason)
{
unsigned long irq_flags;
@@ -905,15 +905,15 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part,
if (part->act_state == XPC_P_INACTIVE) {
XPC_SET_REASON(part, reason, line);
spin_unlock_irqrestore(&part->act_lock, irq_flags);
- if (reason == xpcReactivating) {
+ if (reason == xpReactivating) {
/* we interrupt ourselves to reactivate partition */
xpc_IPI_send_reactivate(part);
}
return;
}
if (part->act_state == XPC_P_DEACTIVATING) {
- if ((part->reason == xpcUnloading && reason != xpcUnloading) ||
- reason == xpcReactivating) {
+ if ((part->reason == xpUnloading && reason != xpUnloading) ||
+ reason == xpReactivating) {
XPC_SET_REASON(part, reason, line);
}
spin_unlock_irqrestore(&part->act_lock, irq_flags);
@@ -982,10 +982,10 @@ xpc_discovery(void)
int max_regions;
int nasid;
struct xpc_rsvd_page *rp;
- partid_t partid;
+ short partid;
struct xpc_partition *part;
u64 *discovered_nasids;
- enum xpc_retval ret;
+ enum xp_retval ret;
remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE +
xp_nasid_mask_bytes,
@@ -1063,12 +1063,12 @@ xpc_discovery(void)
ret = xpc_get_remote_rp(nasid, discovered_nasids,
remote_rp, &remote_rp_pa);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_dbg(xpc_part, "unable to get reserved page "
"from nasid %d, reason=%d\n", nasid,
ret);
- if (ret == xpcLocalPartid)
+ if (ret == xpLocalPartid)
break;
continue;
@@ -1082,7 +1082,7 @@ xpc_discovery(void)
/* pull over the cross partition variables */
ret = xpc_get_remote_vars(remote_vars_pa, remote_vars);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_dbg(xpc_part, "unable to get XPC variables "
"from nasid %d, reason=%d\n", nasid,
ret);
@@ -1116,7 +1116,7 @@ xpc_discovery(void)
"register xp_addr region 0x%016lx\n",
partid, remote_vars->amos_page_pa);
- XPC_SET_REASON(part, xpcPhysAddrRegFailed,
+ XPC_SET_REASON(part, xpPhysAddrRegFailed,
__LINE__);
break;
}
@@ -1151,8 +1151,8 @@ xpc_discovery(void)
* Given a partid, get the nasids owned by that partition from the
* remote partition's reserved page.
*/
-enum xpc_retval
-xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask)
+enum xp_retval
+xpc_initiate_partid_to_nasids(short partid, void *nasid_mask)
{
struct xpc_partition *part;
u64 part_nasid_pa;
@@ -1160,7 +1160,7 @@ xpc_initiate_partid_to_nasids(partid_t partid, void *nasid_mask)
part = &xpc_partitions[partid];
if (part->remote_rp_pa == 0)
- return xpcPartitionDown;
+ return xpPartitionDown;
memset(nasid_mask, 0, XP_NASID_MASK_BYTES);
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index a9543c65814d..822dc8e8d7f0 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -166,7 +166,7 @@ struct device *xpnet = &xpnet_dbg_subname;
* Packet was recevied by XPC and forwarded to us.
*/
static void
-xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg)
+xpnet_receive(short partid, int channel, struct xpnet_message *msg)
{
struct sk_buff *skb;
bte_result_t bret;
@@ -282,7 +282,7 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg)
* state or message reception on a connection.
*/
static void
-xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel,
+xpnet_connection_activity(enum xp_retval reason, short partid, int channel,
void *data, void *key)
{
long bp;
@@ -291,13 +291,13 @@ xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel,
DBUG_ON(channel != XPC_NET_CHANNEL);
switch (reason) {
- case xpcMsgReceived: /* message received */
+ case xpMsgReceived: /* message received */
DBUG_ON(data == NULL);
xpnet_receive(partid, channel, (struct xpnet_message *)data);
break;
- case xpcConnected: /* connection completed to a partition */
+ case xpConnected: /* connection completed to a partition */
spin_lock_bh(&xpnet_broadcast_lock);
xpnet_broadcast_partitions |= 1UL << (partid - 1);
bp = xpnet_broadcast_partitions;
@@ -330,7 +330,7 @@ xpnet_connection_activity(enum xpc_retval reason, partid_t partid, int channel,
static int
xpnet_dev_open(struct net_device *dev)
{
- enum xpc_retval ret;
+ enum xp_retval ret;
dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, "
"%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity,
@@ -340,7 +340,7 @@ xpnet_dev_open(struct net_device *dev)
ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL,
XPNET_MSG_SIZE, XPNET_MSG_NENTRIES,
XPNET_MAX_KTHREADS, XPNET_MAX_IDLE_KTHREADS);
- if (ret != xpcSuccess) {
+ if (ret != xpSuccess) {
dev_err(xpnet, "ifconfig up of %s failed on XPC connect, "
"ret=%d\n", dev->name, ret);
@@ -407,7 +407,7 @@ xpnet_dev_get_stats(struct net_device *dev)
* release the skb and then release our pending message structure.
*/
static void
-xpnet_send_completed(enum xpc_retval reason, partid_t partid, int channel,
+xpnet_send_completed(enum xp_retval reason, short partid, int channel,
void *__qm)
{
struct xpnet_pending_msg *queued_msg = (struct xpnet_pending_msg *)__qm;
@@ -439,12 +439,12 @@ static int
xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xpnet_pending_msg *queued_msg;
- enum xpc_retval ret;
+ enum xp_retval ret;
struct xpnet_message *msg;
u64 start_addr, end_addr;
long dp;
u8 second_mac_octet;
- partid_t dest_partid;
+ short dest_partid;
struct xpnet_dev_private *priv;
u16 embedded_bytes;
@@ -528,7 +528,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL,
XPC_NOWAIT, (void **)&msg);
- if (unlikely(ret != xpcSuccess))
+ if (unlikely(ret != xpSuccess))
continue;
msg->embedded_bytes = embedded_bytes;
@@ -557,7 +557,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg,
xpnet_send_completed, queued_msg);
- if (unlikely(ret != xpcSuccess)) {
+ if (unlikely(ret != xpSuccess)) {
atomic_dec(&queued_msg->use_count);
continue;
}
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 02ff3d19b1cc..00e48e2a9c11 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -961,7 +961,7 @@ static int sony_nc_resume(struct acpi_device *device)
ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
item->value, NULL);
if (ret < 0) {
- printk("%s: %d\n", __FUNCTION__, ret);
+ printk("%s: %d\n", __func__, ret);
break;
}
}
@@ -1453,7 +1453,7 @@ static struct sonypi_eventtypes type4_events[] = {
udelay(1); \
if (!n) \
dprintk("command failed at %s : %s (line %d)\n", \
- __FILE__, __FUNCTION__, __LINE__); \
+ __FILE__, __func__, __LINE__); \
}
static u8 sony_pic_call1(u8 dev)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6cb781262f94..3f28f6eabdbf 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
* 02110-1301, USA.
*/
-#define TPACPI_VERSION "0.19"
+#define TPACPI_VERSION "0.20"
#define TPACPI_SYSFS_VERSION 0x020200
/*
@@ -67,6 +67,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
@@ -85,6 +86,8 @@
#define TP_CMOS_VOLUME_MUTE 2
#define TP_CMOS_BRIGHTNESS_UP 4
#define TP_CMOS_BRIGHTNESS_DOWN 5
+#define TP_CMOS_THINKLIGHT_ON 12
+#define TP_CMOS_THINKLIGHT_OFF 13
/* NVRAM Addresses */
enum tp_nvram_addr {
@@ -133,8 +136,12 @@ enum {
#define TPACPI_PROC_DIR "ibm"
#define TPACPI_ACPI_EVENT_PREFIX "ibm"
#define TPACPI_DRVR_NAME TPACPI_FILE
+#define TPACPI_DRVR_SHORTNAME "tpacpi"
#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
+#define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd"
+#define TPACPI_WORKQUEUE_NAME "ktpacpid"
+
#define TPACPI_MAX_ACPI_ARGS 3
/* Debugging */
@@ -225,6 +232,7 @@ static struct {
u32 light:1;
u32 light_status:1;
u32 bright_16levels:1;
+ u32 bright_acpimode:1;
u32 wan:1;
u32 fan_ctrl_status_undef:1;
u32 input_device_registered:1;
@@ -236,6 +244,11 @@ static struct {
u32 hotkey_poll_active:1;
} tp_features;
+static struct {
+ u16 hotkey_mask_ff:1;
+ u16 bright_cmos_ec_unsync:1;
+} tp_warned;
+
struct thinkpad_id_data {
unsigned int vendor; /* ThinkPad vendor:
* PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
@@ -246,7 +259,8 @@ struct thinkpad_id_data {
u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
u16 ec_model;
- char *model_str;
+ char *model_str; /* ThinkPad T43 */
+ char *nummodel_str; /* 9384A9C for a 9384-A9C model */
};
static struct thinkpad_id_data thinkpad_id;
@@ -259,6 +273,16 @@ static enum {
static int experimental;
static u32 dbg_level;
+static struct workqueue_struct *tpacpi_wq;
+
+/* Special LED class that can defer work */
+struct tpacpi_led_classdev {
+ struct led_classdev led_classdev;
+ struct work_struct work;
+ enum led_brightness new_brightness;
+ unsigned int led;
+};
+
/****************************************************************************
****************************************************************************
*
@@ -807,6 +831,80 @@ static int parse_strtoul(const char *buf,
return 0;
}
+static int __init tpacpi_query_bcl_levels(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ int rc;
+
+ if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+ obj = (union acpi_object *)buffer.pointer;
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+ printk(TPACPI_ERR "Unknown _BCL data, "
+ "please report this to %s\n", TPACPI_MAIL);
+ rc = 0;
+ } else {
+ rc = obj->package.count;
+ }
+ } else {
+ return 0;
+ }
+
+ kfree(buffer.pointer);
+ return rc;
+}
+
+static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
+ u32 lvl, void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("_BCL", name, sizeof(name) - 1)) {
+ BUG_ON(!rv || !*rv);
+ **(int **)rv = tpacpi_query_bcl_levels(handle);
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+}
+
+/*
+ * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
+ */
+static int __init tpacpi_check_std_acpi_brightness_support(void)
+{
+ int status;
+ int bcl_levels = 0;
+ void *bcl_ptr = &bcl_levels;
+
+ if (!vid_handle) {
+ TPACPI_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /*
+ * Search for a _BCL method, and execute it. This is safe on all
+ * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
+ * BIOS in ACPI backlight control mode. We do NOT have to care
+ * about calling the _BCL method in an enabled video device, any
+ * will do for our purposes.
+ */
+
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+ tpacpi_acpi_walk_find_bcl, NULL,
+ &bcl_ptr);
+
+ if (ACPI_SUCCESS(status) && bcl_levels > 2) {
+ tp_features.bright_acpimode = 1;
+ return (bcl_levels - 2);
+ }
+
+ return 0;
+}
+
/*************************************************************************
* thinkpad-acpi driver attributes
*/
@@ -909,12 +1007,14 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
thinkpad_id.ec_version_str : "unknown");
if (thinkpad_id.vendor && thinkpad_id.model_str)
- printk(TPACPI_INFO "%s %s\n",
+ printk(TPACPI_INFO "%s %s, model %s\n",
(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
"IBM" : ((thinkpad_id.vendor ==
PCI_VENDOR_ID_LENOVO) ?
"Lenovo" : "Unknown vendor"),
- thinkpad_id.model_str);
+ thinkpad_id.model_str,
+ (thinkpad_id.nummodel_str) ?
+ thinkpad_id.nummodel_str : "unknown");
return 0;
}
@@ -1107,6 +1207,19 @@ static int hotkey_mask_set(u32 mask)
int rc = 0;
if (tp_features.hotkey_mask) {
+ if (!tp_warned.hotkey_mask_ff &&
+ (mask == 0xffff || mask == 0xffffff ||
+ mask == 0xffffffff)) {
+ tp_warned.hotkey_mask_ff = 1;
+ printk(TPACPI_NOTICE
+ "setting the hotkey mask to 0x%08x is likely "
+ "not the best way to go about it\n", mask);
+ printk(TPACPI_NOTICE
+ "please consider using the driver defaults, "
+ "and refer to up-to-date thinkpad-acpi "
+ "documentation\n");
+ }
+
HOTKEY_CONFIG_CRITICAL_START
for (i = 0; i < 32; i++) {
u32 m = 1 << i;
@@ -1427,8 +1540,7 @@ static void hotkey_poll_setup(int may_warn)
(tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
if (!tpacpi_hotkey_task) {
tpacpi_hotkey_task = kthread_run(hotkey_kthread,
- NULL,
- TPACPI_FILE "d");
+ NULL, TPACPI_NVRAM_KTHREAD_NAME);
if (IS_ERR(tpacpi_hotkey_task)) {
tpacpi_hotkey_task = NULL;
printk(TPACPI_ERR
@@ -1887,6 +1999,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ /* These either have to go through ACPI video, or
+ * act like in the IBM ThinkPads, so don't ever
+ * enable them by default */
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
@@ -2091,6 +2206,32 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
}
+ /* Do not issue duplicate brightness change events to
+ * userspace */
+ if (!tp_features.bright_acpimode)
+ /* update bright_acpimode... */
+ tpacpi_check_std_acpi_brightness_support();
+
+ if (tp_features.bright_acpimode) {
+ printk(TPACPI_INFO
+ "This ThinkPad has standard ACPI backlight "
+ "brightness control, supported by the ACPI "
+ "video driver\n");
+ printk(TPACPI_NOTICE
+ "Disabling thinkpad-acpi brightness events "
+ "by default...\n");
+
+ /* The hotkey_reserved_mask change below is not
+ * necessary while the keys are at KEY_RESERVED in the
+ * default map, but better safe than sorry, leave it
+ * here as a marker of what we have to do, especially
+ * when we finally become able to set this at runtime
+ * on response to X.org requests */
+ hotkey_reserved_mask |=
+ (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
+ | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
+ }
+
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
res = hotkey_status_set(1);
@@ -3110,13 +3251,82 @@ static struct ibm_struct video_driver_data = {
TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
+static int light_get_status(void)
+{
+ int status = 0;
+
+ if (tp_features.light_status) {
+ if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+ return -EIO;
+ return (!!status);
+ }
+
+ return -ENXIO;
+}
+
+static int light_set_status(int status)
+{
+ int rc;
+
+ if (tp_features.light) {
+ if (cmos_handle) {
+ rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
+ (status)?
+ TP_CMOS_THINKLIGHT_ON :
+ TP_CMOS_THINKLIGHT_OFF);
+ } else {
+ rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
+ (status)? 1 : 0);
+ }
+ return (rc)? 0 : -EIO;
+ }
+
+ return -ENXIO;
+}
+
+static void light_set_status_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ light_set_status((data->new_brightness != LED_OFF));
+}
+
+static void light_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(led_cdev,
+ struct tpacpi_led_classdev,
+ led_classdev);
+ data->new_brightness = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
+{
+ return (light_get_status() == 1)? LED_FULL : LED_OFF;
+}
+
+static struct tpacpi_led_classdev tpacpi_led_thinklight = {
+ .led_classdev = {
+ .name = "tpacpi::thinklight",
+ .brightness_set = &light_sysfs_set,
+ .brightness_get = &light_sysfs_get,
+ }
+};
+
static int __init light_init(struct ibm_init_struct *iibm)
{
+ int rc = 0;
+
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
TPACPI_ACPIHANDLE_INIT(ledb);
TPACPI_ACPIHANDLE_INIT(lght);
TPACPI_ACPIHANDLE_INIT(cmos);
+ INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker);
/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -3130,13 +3340,31 @@ static int __init light_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
str_supported(tp_features.light));
- return (tp_features.light)? 0 : 1;
+ if (tp_features.light) {
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_led_thinklight.led_classdev);
+ }
+
+ if (rc < 0) {
+ tp_features.light = 0;
+ tp_features.light_status = 0;
+ } else {
+ rc = (tp_features.light)? 0 : 1;
+ }
+ return rc;
+}
+
+static void light_exit(void)
+{
+ led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
+ if (work_pending(&tpacpi_led_thinklight.work))
+ flush_workqueue(tpacpi_wq);
}
static int light_read(char *p)
{
int len = 0;
- int status = 0;
+ int status;
if (!tp_features.light) {
len += sprintf(p + len, "status:\t\tnot supported\n");
@@ -3144,8 +3372,9 @@ static int light_read(char *p)
len += sprintf(p + len, "status:\t\tunknown\n");
len += sprintf(p + len, "commands:\ton, off\n");
} else {
- if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
- return -EIO;
+ status = light_get_status();
+ if (status < 0)
+ return status;
len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
len += sprintf(p + len, "commands:\ton, off\n");
}
@@ -3155,37 +3384,29 @@ static int light_read(char *p)
static int light_write(char *buf)
{
- int cmos_cmd, lght_cmd;
char *cmd;
- int success;
+ int newstatus = 0;
if (!tp_features.light)
return -ENODEV;
while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "on") == 0) {
- cmos_cmd = 0x0c;
- lght_cmd = 1;
+ newstatus = 1;
} else if (strlencmp(cmd, "off") == 0) {
- cmos_cmd = 0x0d;
- lght_cmd = 0;
+ newstatus = 0;
} else
return -EINVAL;
-
- success = cmos_handle ?
- acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
- acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
- if (!success)
- return -EIO;
}
- return 0;
+ return light_set_status(newstatus);
}
static struct ibm_struct light_driver_data = {
.name = "light",
.read = light_read,
.write = light_write,
+ .exit = light_exit,
};
/*************************************************************************
@@ -3583,6 +3804,12 @@ enum { /* For TPACPI_LED_OLD */
TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
};
+enum led_status_t {
+ TPACPI_LED_OFF = 0,
+ TPACPI_LED_ON,
+ TPACPI_LED_BLINK,
+};
+
static enum led_access_mode led_supported;
TPACPI_HANDLE(led, ec, "SLED", /* 570 */
@@ -3591,8 +3818,174 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
"LED", /* all others */
); /* R30, R31 */
+#define TPACPI_LED_NUMLEDS 8
+static struct tpacpi_led_classdev *tpacpi_leds;
+static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
+static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
+ /* there's a limit of 19 chars + NULL before 2.6.26 */
+ "tpacpi::power",
+ "tpacpi:orange:batt",
+ "tpacpi:green:batt",
+ "tpacpi::dock_active",
+ "tpacpi::bay_active",
+ "tpacpi::dock_batt",
+ "tpacpi::unknown_led",
+ "tpacpi::standby",
+};
+
+static int led_get_status(unsigned int led)
+{
+ int status;
+ enum led_status_t led_s;
+
+ switch (led_supported) {
+ case TPACPI_LED_570:
+ if (!acpi_evalf(ec_handle,
+ &status, "GLED", "dd", 1 << led))
+ return -EIO;
+ led_s = (status == 0)?
+ TPACPI_LED_OFF :
+ ((status == 1)?
+ TPACPI_LED_ON :
+ TPACPI_LED_BLINK);
+ tpacpi_led_state_cache[led] = led_s;
+ return led_s;
+ default:
+ return -ENXIO;
+ }
+
+ /* not reached */
+}
+
+static int led_set_status(unsigned int led, enum led_status_t ledstatus)
+{
+ /* off, on, blink. Index is led_status_t */
+ static const int const led_sled_arg1[] = { 0, 1, 3 };
+ static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
+ static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
+ static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+ int rc = 0;
+
+ switch (led_supported) {
+ case TPACPI_LED_570:
+ /* 570 */
+ led = 1 << led;
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_sled_arg1[ledstatus]))
+ rc = -EIO;
+ break;
+ case TPACPI_LED_OLD:
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+ led = 1 << led;
+ rc = ec_write(TPACPI_LED_EC_HLMS, led);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLBL,
+ led * led_exp_hlbl[ledstatus]);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLCL,
+ led * led_exp_hlcl[ledstatus]);
+ break;
+ case TPACPI_LED_NEW:
+ /* all others */
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_led_arg1[ledstatus]))
+ rc = -EIO;
+ break;
+ default:
+ rc = -ENXIO;
+ }
+
+ if (!rc)
+ tpacpi_led_state_cache[led] = ledstatus;
+
+ return rc;
+}
+
+static void led_sysfs_set_status(unsigned int led,
+ enum led_brightness brightness)
+{
+ led_set_status(led,
+ (brightness == LED_OFF) ?
+ TPACPI_LED_OFF :
+ (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ?
+ TPACPI_LED_BLINK : TPACPI_LED_ON);
+}
+
+static void led_set_status_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ led_sysfs_set_status(data->led, data->new_brightness);
+}
+
+static void led_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ data->new_brightness = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static int led_sysfs_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on, unsigned long *delay_off)
+{
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ /* Can we choose the flash rate? */
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* yes. set them to the hardware blink rate (1 Hz) */
+ *delay_on = 500; /* ms */
+ *delay_off = 500; /* ms */
+ } else if ((*delay_on != 500) || (*delay_off != 500))
+ return -EINVAL;
+
+ data->new_brightness = TPACPI_LED_BLINK;
+ queue_work(tpacpi_wq, &data->work);
+
+ return 0;
+}
+
+static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev)
+{
+ int rc;
+
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ rc = led_get_status(data->led);
+
+ if (rc == TPACPI_LED_OFF || rc < 0)
+ rc = LED_OFF; /* no error handling in led class :( */
+ else
+ rc = LED_FULL;
+
+ return rc;
+}
+
+static void led_exit(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+ if (tpacpi_leds[i].led_classdev.name)
+ led_classdev_unregister(&tpacpi_leds[i].led_classdev);
+ }
+
+ kfree(tpacpi_leds);
+ tpacpi_leds = NULL;
+}
+
static int __init led_init(struct ibm_init_struct *iibm)
{
+ unsigned int i;
+ int rc;
+
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
TPACPI_ACPIHANDLE_INIT(led);
@@ -3613,10 +4006,41 @@ static int __init led_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
str_supported(led_supported), led_supported);
+ tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
+ GFP_KERNEL);
+ if (!tpacpi_leds) {
+ printk(TPACPI_ERR "Out of memory for LED data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+ tpacpi_leds[i].led = i;
+
+ tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set;
+ tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set;
+ if (led_supported == TPACPI_LED_570)
+ tpacpi_leds[i].led_classdev.brightness_get =
+ &led_sysfs_get;
+
+ tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i];
+
+ INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker);
+
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_leds[i].led_classdev);
+ if (rc < 0) {
+ tpacpi_leds[i].led_classdev.name = NULL;
+ led_exit();
+ return rc;
+ }
+ }
+
return (led_supported != TPACPI_LED_NONE)? 0 : 1;
}
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+#define str_led_status(s) \
+ ((s) == TPACPI_LED_OFF ? "off" : \
+ ((s) == TPACPI_LED_ON ? "on" : "blinking"))
static int led_read(char *p)
{
@@ -3632,11 +4056,11 @@ static int led_read(char *p)
/* 570 */
int i, status;
for (i = 0; i < 8; i++) {
- if (!acpi_evalf(ec_handle,
- &status, "GLED", "dd", 1 << i))
+ status = led_get_status(i);
+ if (status < 0)
return -EIO;
len += sprintf(p + len, "%d:\t\t%s\n",
- i, led_status(status));
+ i, str_led_status(status));
}
}
@@ -3646,16 +4070,11 @@ static int led_read(char *p)
return len;
}
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
static int led_write(char *buf)
{
char *cmd;
- int led, ind, ret;
+ int led, rc;
+ enum led_status_t s;
if (!led_supported)
return -ENODEV;
@@ -3665,38 +4084,18 @@ static int led_write(char *buf)
return -EINVAL;
if (strstr(cmd, "off")) {
- ind = 0;
+ s = TPACPI_LED_OFF;
} else if (strstr(cmd, "on")) {
- ind = 1;
+ s = TPACPI_LED_ON;
} else if (strstr(cmd, "blink")) {
- ind = 2;
- } else
- return -EINVAL;
-
- if (led_supported == TPACPI_LED_570) {
- /* 570 */
- led = 1 << led;
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_sled_arg1[ind]))
- return -EIO;
- } else if (led_supported == TPACPI_LED_OLD) {
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
- led = 1 << led;
- ret = ec_write(TPACPI_LED_EC_HLMS, led);
- if (ret >= 0)
- ret = ec_write(TPACPI_LED_EC_HLBL,
- led * led_exp_hlbl[ind]);
- if (ret >= 0)
- ret = ec_write(TPACPI_LED_EC_HLCL,
- led * led_exp_hlcl[ind]);
- if (ret < 0)
- return ret;
+ s = TPACPI_LED_BLINK;
} else {
- /* all others */
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_led_arg1[ind]))
- return -EIO;
+ return -EINVAL;
}
+
+ rc = led_set_status(led, s);
+ if (rc < 0)
+ return rc;
}
return 0;
@@ -3706,6 +4105,7 @@ static struct ibm_struct led_driver_data = {
.name = "led",
.read = led_read,
.write = led_write,
+ .exit = led_exit,
};
/*************************************************************************
@@ -4170,8 +4570,16 @@ static struct ibm_struct ecdump_driver_data = {
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+enum {
+ TP_EC_BACKLIGHT = 0x31,
+
+ /* TP_EC_BACKLIGHT bitmasks */
+ TP_EC_BACKLIGHT_LVLMSK = 0x1F,
+ TP_EC_BACKLIGHT_CMDMSK = 0xE0,
+ TP_EC_BACKLIGHT_MAPSW = 0x20,
+};
+
static struct backlight_device *ibm_backlight_device;
-static int brightness_offset = 0x31;
static int brightness_mode;
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
@@ -4180,16 +4588,24 @@ static struct mutex brightness_mutex;
/*
* ThinkPads can read brightness from two places: EC 0x31, or
* CMOS NVRAM byte 0x5E, bits 0-3.
+ *
+ * EC 0x31 has the following layout
+ * Bit 7: unknown function
+ * Bit 6: unknown function
+ * Bit 5: Z: honour scale changes, NZ: ignore scale changes
+ * Bit 4: must be set to zero to avoid problems
+ * Bit 3-0: backlight brightness level
+ *
+ * brightness_get_raw returns status data in the EC 0x31 layout
*/
-static int brightness_get(struct backlight_device *bd)
+static int brightness_get_raw(int *status)
{
u8 lec = 0, lcmos = 0, level = 0;
if (brightness_mode & 1) {
- if (!acpi_ec_read(brightness_offset, &lec))
+ if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
return -EIO;
- lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
- level = lec;
+ level = lec & TP_EC_BACKLIGHT_LVLMSK;
};
if (brightness_mode & 2) {
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
@@ -4199,16 +4615,27 @@ static int brightness_get(struct backlight_device *bd)
level = lcmos;
}
- if (brightness_mode == 3 && lec != lcmos) {
- printk(TPACPI_ERR
- "CMOS NVRAM (%u) and EC (%u) do not agree "
- "on display brightness level\n",
- (unsigned int) lcmos,
- (unsigned int) lec);
- return -EIO;
+ if (brightness_mode == 3) {
+ *status = lec; /* Prefer EC, CMOS is just a backing store */
+ lec &= TP_EC_BACKLIGHT_LVLMSK;
+ if (lec == lcmos)
+ tp_warned.bright_cmos_ec_unsync = 0;
+ else {
+ if (!tp_warned.bright_cmos_ec_unsync) {
+ printk(TPACPI_ERR
+ "CMOS NVRAM (%u) and EC (%u) do not "
+ "agree on display brightness level\n",
+ (unsigned int) lcmos,
+ (unsigned int) lec);
+ tp_warned.bright_cmos_ec_unsync = 1;
+ }
+ return -EIO;
+ }
+ } else {
+ *status = level;
}
- return level;
+ return 0;
}
/* May return EINTR which can always be mapped to ERESTARTSYS */
@@ -4216,19 +4643,22 @@ static int brightness_set(int value)
{
int cmos_cmd, inc, i, res;
int current_value;
+ int command_bits;
- if (value > ((tp_features.bright_16levels)? 15 : 7))
+ if (value > ((tp_features.bright_16levels)? 15 : 7) ||
+ value < 0)
return -EINVAL;
res = mutex_lock_interruptible(&brightness_mutex);
if (res < 0)
return res;
- current_value = brightness_get(NULL);
- if (current_value < 0) {
- res = current_value;
+ res = brightness_get_raw(&current_value);
+ if (res < 0)
goto errout;
- }
+
+ command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
+ current_value &= TP_EC_BACKLIGHT_LVLMSK;
cmos_cmd = value > current_value ?
TP_CMOS_BRIGHTNESS_UP :
@@ -4243,7 +4673,8 @@ static int brightness_set(int value)
goto errout;
}
if ((brightness_mode & 1) &&
- !acpi_ec_write(brightness_offset, i + inc)) {
+ !acpi_ec_write(TP_EC_BACKLIGHT,
+ (i + inc) | command_bits)) {
res = -EIO;
goto errout;;
}
@@ -4266,106 +4697,23 @@ static int brightness_update_status(struct backlight_device *bd)
bd->props.brightness : 0);
}
-static struct backlight_ops ibm_backlight_data = {
- .get_brightness = brightness_get,
- .update_status = brightness_update_status,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int __init tpacpi_query_bcll_levels(acpi_handle handle)
-{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- int rc;
-
- if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
- obj = (union acpi_object *)buffer.pointer;
- if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
- printk(TPACPI_ERR "Unknown BCLL data, "
- "please report this to %s\n", TPACPI_MAIL);
- rc = 0;
- } else {
- rc = obj->package.count;
- }
- } else {
- return 0;
- }
-
- kfree(buffer.pointer);
- return rc;
-}
-
-static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
-
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("BCLL", name, sizeof(name) - 1)) {
- if (tpacpi_query_bcll_levels(handle) == 16) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
- } else {
- return AE_OK;
- }
-}
-
-static int __init brightness_check_levels(void)
+static int brightness_get(struct backlight_device *bd)
{
- int status;
- void *found_node = NULL;
+ int status, res;
- if (!vid_handle) {
- TPACPI_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a BCLL package with 16 levels */
- status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
- brightness_find_bcll, NULL,
- &found_node);
-
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
-static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
+ res = brightness_get_raw(&status);
+ if (res < 0)
+ return 0; /* FIXME: teach backlight about error handling */
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("_BCL", name, sizeof(name) - 1)) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
+ return status & TP_EC_BACKLIGHT_LVLMSK;
}
-static int __init brightness_check_std_acpi_support(void)
-{
- int status;
- void *found_node = NULL;
-
- if (!vid_handle) {
- TPACPI_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a _BCL method, but don't execute it */
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
- brightness_find_bcl, NULL, &found_node);
+static struct backlight_ops ibm_backlight_data = {
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+};
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
+/* --------------------------------------------------------------------- */
static int __init brightness_init(struct ibm_init_struct *iibm)
{
@@ -4375,13 +4723,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
mutex_init(&brightness_mutex);
- if (!brightness_enable) {
- dbg_printk(TPACPI_DBG_INIT,
- "brightness support disabled by "
- "module parameter\n");
- return 1;
- } else if (brightness_enable > 1) {
- if (brightness_check_std_acpi_support()) {
+ /*
+ * We always attempt to detect acpi support, so as to switch
+ * Lenovo Vista BIOS to ACPI brightness mode even if we are not
+ * going to publish a backlight interface
+ */
+ b = tpacpi_check_std_acpi_brightness_support();
+ if (b > 0) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+ printk(TPACPI_NOTICE
+ "Lenovo BIOS switched to ACPI backlight "
+ "control mode\n");
+ }
+ if (brightness_enable > 1) {
printk(TPACPI_NOTICE
"standard ACPI backlight interface "
"available, not loading native one...\n");
@@ -4389,6 +4743,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
}
}
+ if (!brightness_enable) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "brightness support disabled by "
+ "module parameter\n");
+ return 1;
+ }
+
+ if (b > 16) {
+ printk(TPACPI_ERR
+ "Unsupported brightness interface, "
+ "please contact %s\n", TPACPI_MAIL);
+ return 1;
+ }
+ if (b == 16)
+ tp_features.bright_16levels = 1;
+
if (!brightness_mode) {
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
brightness_mode = 2;
@@ -4402,12 +4772,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
if (brightness_mode > 3)
return -EINVAL;
- tp_features.bright_16levels =
- thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
- brightness_check_levels();
-
- b = brightness_get(NULL);
- if (b < 0)
+ if (brightness_get_raw(&b) < 0)
return 1;
if (tp_features.bright_16levels)
@@ -4425,7 +4790,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
ibm_backlight_device->props.max_brightness =
(tp_features.bright_16levels)? 15 : 7;
- ibm_backlight_device->props.brightness = b;
+ ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
backlight_update_status(ibm_backlight_device);
return 0;
@@ -5046,11 +5411,11 @@ static void fan_watchdog_reset(void)
if (fan_watchdog_maxinterval > 0 &&
tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
fan_watchdog_active = 1;
- if (!schedule_delayed_work(&fan_watchdog_task,
+ if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval
* 1000))) {
printk(TPACPI_ERR
- "failed to schedule the fan watchdog, "
+ "failed to queue the fan watchdog, "
"watchdog will not trigger\n");
}
} else
@@ -5420,7 +5785,7 @@ static void fan_exit(void)
&driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task);
- flush_scheduled_work();
+ flush_workqueue(tpacpi_wq);
}
static int fan_read(char *p)
@@ -5826,10 +6191,13 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
GFP_KERNEL);
- if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+ if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
kfree(tp->model_str);
tp->model_str = NULL;
}
+
+ tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME),
+ GFP_KERNEL);
}
static int __init probe_for_thinkpad(void)
@@ -6071,6 +6439,9 @@ static void thinkpad_acpi_module_exit(void)
if (proc_dir)
remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
+ if (tpacpi_wq)
+ destroy_workqueue(tpacpi_wq);
+
kfree(thinkpad_id.bios_version_str);
kfree(thinkpad_id.ec_version_str);
kfree(thinkpad_id.model_str);
@@ -6101,6 +6472,12 @@ static int __init thinkpad_acpi_module_init(void)
TPACPI_ACPIHANDLE_INIT(ecrd);
TPACPI_ACPIHANDLE_INIT(ecwr);
+ tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME);
+ if (!tpacpi_wq) {
+ thinkpad_acpi_module_exit();
+ return -ENOMEM;
+ }
+
proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
if (!proc_dir) {
printk(TPACPI_ERR
@@ -6223,6 +6600,8 @@ static int __init thinkpad_acpi_module_init(void)
/* Please remove this in year 2009 */
MODULE_ALIAS("ibm_acpi");
+MODULE_ALIAS(TPACPI_DRVR_SHORTNAME);
+
/*
* DMI matching for module autoloading
*
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 365024b83d3d..35508584ac2a 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -340,7 +340,7 @@ checkstatus:
/* SPI R3, R4, or R7 == R1 + 4 bytes */
case MMC_RSP_SPI_R3:
- cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp));
+ cmd->resp[1] = get_unaligned_be32(cp);
break;
/* SPI R1 == just one status byte */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 95244a7e7353..da5fecad74d9 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -213,9 +213,10 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
void __iomem *base = host->base;
char *ptr = buffer;
u32 status;
+ int host_remain = host->size;
do {
- int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+ int count = host_remain - (readl(base + MMCIFIFOCNT) << 2);
if (count > remain)
count = remain;
@@ -227,6 +228,7 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
ptr += count;
remain -= count;
+ host_remain -= count;
if (remain == 0)
break;
@@ -423,7 +425,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->cclk = host->mclk;
} else {
clk = host->mclk / (2 * ios->clock) - 1;
- if (clk > 256)
+ if (clk >= 256)
clk = 255;
host->cclk = host->mclk / (2 * (clk + 1));
}
@@ -510,6 +512,18 @@ static int mmci_probe(struct amba_device *dev, void *id)
host->plat = plat;
host->mclk = clk_get_rate(host->clk);
+ /*
+ * According to the spec, mclk is max 100 MHz,
+ * so we try to adjust the clock down to this,
+ * (if possible).
+ */
+ if (host->mclk > 100000000) {
+ ret = clk_set_rate(host->clk, 100000000);
+ if (ret < 0)
+ goto clk_disable;
+ host->mclk = clk_get_rate(host->clk);
+ DBG(host, "eventual mclk rate: %u Hz\n", host->mclk);
+ }
host->mmc = mmc;
host->base = ioremap(dev->res.start, SZ_4K);
if (!host->base) {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7fb02e177a3d..299118de8933 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -187,7 +187,7 @@ struct sdhci_host {
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
struct mmc_data *data; /* Current data request */
- int data_early:1; /* Data finished before cmd */
+ unsigned int data_early:1; /* Data finished before cmd */
struct scatterlist *cur_sg; /* We're working on this */
int num_sg; /* Entries left */
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index e812df607a5c..fcd1aeccdf93 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf);
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len);
+ size_t *retlen, void **virt, resource_size_t *phys);
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
@@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
return ret;
}
-static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift);
- *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+ *virt = map->virt + cfi->chips[chipnum].start + ofs;
*retlen = 0;
+ if (phys)
+ *phys = map->phys + cfi->chips[chipnum].start + ofs;
while (len) {
unsigned long thislen;
@@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
return 0;
}
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index bf485ff49457..0399be178620 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = mtd->priv + from;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
+ *virt = mtd->priv + from;
*retlen = len;
return 0;
}
-static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
- size_t len)
+static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 5f960182da95..c7987b1c5e01 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
- u_char *start = mtd->priv;
-
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = start + from;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
+ *virt = mtd->priv + from;
*retlen = len;
return 0;
}
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len)
+static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 7060a0895ce2..bc9981749064 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1);
- pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
+ pmc551_point(mtd, instr->addr, instr->len, &retlen,
+ (void **)&ptr, NULL);
if (soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot
@@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
}
soff_hi += priv->asize;
pmc551_point(mtd, (priv->base_map0 | soff_hi),
- priv->asize, &retlen, &ptr);
+ priv->asize, &retlen,
+ (void **)&ptr, NULL);
}
memset(ptr, 0xff, eoff_lo);
}
@@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char ** mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi;
@@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
return -EINVAL;
}
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
@@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
priv->curr_map0 = soff_hi;
}
- *mtdbuf = priv->start + soff_lo;
+ *virt = priv->start + soff_lo;
*retlen = len;
return 0;
}
-static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
- size_t len)
+static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n");
@@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
- pmc551_point(mtd, from, len, retlen, &ptr);
+ pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
@@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
goto out;
}
soff_hi += priv->asize;
- pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ pmc551_point(mtd, soff_hi, priv->asize, retlen,
+ (void **)&ptr, NULL);
}
memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo;
@@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
- pmc551_point(mtd, to, len, retlen, &ptr);
+ pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
@@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
goto out;
}
soff_hi += priv->asize;
- pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ pmc551_point(mtd, soff_hi, priv->asize, retlen,
+ (void **)&ptr, NULL);
}
memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo;
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index d293add1857c..cb86db746f28 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -76,8 +76,9 @@ static char *map;
static slram_mtd_list_t *slram_mtdlist = NULL;
static int slram_erase(struct mtd_info *, struct erase_info *);
-static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
+static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
+ resource_size_t *);
+static void slram_unpoint(struct mtd_info *, loff_t, size_t);
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
}
static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
slram_priv_t *priv = mtd->priv;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = priv->start + from;
+ *virt = priv->start + from;
*retlen = len;
return(0);
}
-static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 1bd69aa9e22a..17bc87a43ff4 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -374,7 +374,7 @@ config MTD_REDWOOD
config MTD_SOLUTIONENGINE
tristate "CFI Flash device mapped on Hitachi SolutionEngine"
- depends on SUPERH && MTD_CFI && MTD_REDBOOT_PARTS
+ depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
help
This enables access to the flash chips on the Hitachi SolutionEngine and
similar boards. Say 'Y' if you are building a kernel for such a board.
@@ -480,13 +480,6 @@ config MTD_H720X
This enables access to the flash chips on the Hynix evaluation boards.
If you have such a board, say 'Y'.
-config MTD_MPC1211
- tristate "CFI Flash device mapped on Interface MPC-1211"
- depends on SH_MPC1211 && MTD_CFI
- help
- This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02).
- If you have such a board, say 'Y'.
-
config MTD_OMAP_NOR
tristate "TI OMAP board mappings"
depends on MTD_CFI && ARCH_OMAP
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index a9cbe80f99a0..957fb5f70f5e 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -58,7 +58,6 @@ obj-$(CONFIG_MTD_WALNUT) += walnut.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
-obj-$(CONFIG_MTD_MPC1211) += mpc1211.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
diff --git a/drivers/mtd/maps/mpc1211.c b/drivers/mtd/maps/mpc1211.c
deleted file mode 100644
index 45a00fac88ac..000000000000
--- a/drivers/mtd/maps/mpc1211.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Flash on MPC-1211
- *
- * $Id: mpc1211.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $
- *
- * (C) 2002 Interface, Saito.K & Jeanne
- *
- * GPL'd
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-static struct mtd_info *flash_mtd;
-static struct mtd_partition *parsed_parts;
-
-struct map_info mpc1211_flash_map = {
- .name = "MPC-1211 FLASH",
- .size = 0x80000,
- .bankwidth = 1,
-};
-
-static struct mtd_partition mpc1211_partitions[] = {
- {
- .name = "IPL & ETH-BOOT",
- .offset = 0x00000000,
- .size = 0x10000,
- },
- {
- .name = "Flash FS",
- .offset = 0x00010000,
- .size = MTDPART_SIZ_FULL,
- }
-};
-
-static int __init init_mpc1211_maps(void)
-{
- int nr_parts;
-
- mpc1211_flash_map.phys = 0;
- mpc1211_flash_map.virt = (void __iomem *)P2SEGADDR(0);
-
- simple_map_init(&mpc1211_flash_map);
-
- printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
- flash_mtd = do_map_probe("jedec_probe", &mpc1211_flash_map);
- if (!flash_mtd) {
- printk(KERN_NOTICE "Flash chips not detected at either possible location.\n");
- return -ENXIO;
- }
- printk(KERN_NOTICE "MPC-1211: Flash at 0x%08lx\n", mpc1211_flash_map.virt & 0x1fffffff);
- flash_mtd->module = THIS_MODULE;
-
- parsed_parts = mpc1211_partitions;
- nr_parts = ARRAY_SIZE(mpc1211_partitions);
-
- add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
- return 0;
-}
-
-static void __exit cleanup_mpc1211_maps(void)
-{
- if (parsed_parts)
- del_mtd_partitions(flash_mtd);
- else
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
-}
-
-module_init(init_mpc1211_maps);
-module_exit(cleanup_mpc1211_maps);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Saito.K & Jeanne <ksaito@interface.co.jp>");
-MODULE_DESCRIPTION("MTD map driver for MPC-1211 boards. Interface");
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 14ffb1a9302a..c42f4b83f686 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = {
/****************************************************************************/
int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct map_info *map = mtd->priv;
- *mtdbuf = (u_char *) (map->virt + ((int) from));
+ *virt = map->virt + from;
+ if (phys)
+ *phys = map->phys + from;
*retlen = len;
return(0);
}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index c66902df3171..07c701169344 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
}
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **buf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct mtd_part *part = PART(mtd);
if (from >= mtd->size)
@@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
else if (from + len > mtd->size)
len = mtd->size - from;
return part->master->point (part->master, from + part->offset,
- len, retlen, buf);
+ len, retlen, virt, phys);
}
-static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
struct mtd_part *part = PART(mtd);
- part->master->unpoint (part->master, addr, from + part->offset, len);
+ part->master->unpoint(part->master, from + part->offset, len);
}
static int part_read_oob(struct mtd_info *mtd, loff_t from,
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 414ceaecdb3a..0adb287027a2 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -94,6 +94,24 @@ struct at91_nand_host {
};
/*
+ * Enable NAND.
+ */
+static void at91_nand_enable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 0);
+}
+
+/*
+ * Disable NAND.
+ */
+static void at91_nand_disable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 1);
+}
+
+/*
* Hardware specific access to control-lines
*/
static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -101,11 +119,11 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv;
- if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) {
+ if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE)
- at91_set_gpio_value(host->board->enable_pin, 0);
+ at91_nand_enable(host);
else
- at91_set_gpio_value(host->board->enable_pin, 1);
+ at91_nand_disable(host);
}
if (cmd == NAND_CMD_NONE)
return;
@@ -128,24 +146,6 @@ static int at91_nand_device_ready(struct mtd_info *mtd)
}
/*
- * Enable NAND.
- */
-static void at91_nand_enable(struct at91_nand_host *host)
-{
- if (host->board->enable_pin)
- at91_set_gpio_value(host->board->enable_pin, 0);
-}
-
-/*
- * Disable NAND.
- */
-static void at91_nand_disable(struct at91_nand_host *host)
-{
- if (host->board->enable_pin)
- at91_set_gpio_value(host->board->enable_pin, 1);
-}
-
-/*
* write oob for small pages
*/
static int at91_nand_write_oob_512(struct mtd_info *mtd,
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 9c6573419f5a..fdfb2b2cb734 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -670,7 +670,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
}
skb->protocol = eth_type_trans(skb,dev);
- adapter->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
}
@@ -773,12 +773,12 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
* received board statistics
*/
case CMD_NETWORK_STATISTICS_RESPONSE:
- adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
- adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
- adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
- adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
- adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
- adapter->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
+ dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
+ dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
+ dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
+ dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
+ dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
+ dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
adapter->got[CMD_NETWORK_STATISTICS] = 1;
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);
@@ -794,11 +794,11 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
break;
switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
case 0xffff:
- adapter->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);
break;
case 0xfffe:
- adapter->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
break;
}
@@ -986,7 +986,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb)
return false;
}
- adapter->stats.tx_bytes += nlen;
+ dev->stats.tx_bytes += nlen;
/*
* send the adapter a transmit packet command. Ignore segment and offset
@@ -1041,7 +1041,6 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb)
static void elp_timeout(struct net_device *dev)
{
- elp_device *adapter = dev->priv;
int stat;
stat = inb_status(dev->base_addr);
@@ -1049,7 +1048,7 @@ static void elp_timeout(struct net_device *dev)
if (elp_debug >= 1)
printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat);
dev->trans_start = jiffies;
- adapter->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1113,7 +1112,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
/* If the device is closed, just return the latest stats we have,
- we cannot ask from the adapter without interrupts */
if (!netif_running(dev))
- return &adapter->stats;
+ return &dev->stats;
/* send a get statistics command to the board */
adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
@@ -1126,12 +1125,12 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
- return &adapter->stats;
+ return &dev->stats;
}
}
/* statistics are now up to date */
- return &adapter->stats;
+ return &dev->stats;
}
@@ -1571,7 +1570,6 @@ static int __init elplus_setup(struct net_device *dev)
dev->set_multicast_list = elp_set_mc_list; /* local */
dev->ethtool_ops = &netdev_ethtool_ops; /* local */
- memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
dev->mem_start = dev->mem_end = 0;
err = register_netdev(dev);
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
index 1910cb1dc787..04df2a9002b6 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/3c505.h
@@ -264,7 +264,6 @@ typedef struct {
pcb_struct rx_pcb; /* PCB for foreground receiving */
pcb_struct itx_pcb; /* PCB for background sending */
pcb_struct irx_pcb; /* PCB for background receiving */
- struct net_device_stats stats;
void *dma_buffer;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 54dac0696d91..e6c545fe5f58 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -167,7 +167,6 @@ enum RxFilter {
enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
struct el3_private {
- struct net_device_stats stats;
spinlock_t lock;
/* skb send-queue */
int head, size;
@@ -794,7 +793,6 @@ el3_open(struct net_device *dev)
static void
el3_tx_timeout (struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
@@ -802,7 +800,7 @@ el3_tx_timeout (struct net_device *dev)
"Tx FIFO room %d.\n",
dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
inw(ioaddr + TX_FREE));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
dev->trans_start = jiffies;
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
@@ -820,7 +818,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue (dev);
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
if (el3_debug > 4) {
printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
@@ -881,7 +879,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i = 4;
while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@@ -931,12 +929,11 @@ el3_interrupt(int irq, void *dev_id)
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
}
if (status & TxComplete) { /* Really Tx error. */
- struct el3_private *lp = netdev_priv(dev);
short tx_status;
int i = 4;
while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@@ -1002,7 +999,7 @@ el3_get_stats(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
update_stats(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return &lp->stats;
+ return &dev->stats;
}
/* Update statistics. We change to register window 6, so this should be run
@@ -1012,7 +1009,6 @@ el3_get_stats(struct net_device *dev)
*/
static void update_stats(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
if (el3_debug > 5)
@@ -1021,13 +1017,13 @@ static void update_stats(struct net_device *dev)
outw(StatsDisable, ioaddr + EL3_CMD);
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- lp->stats.tx_carrier_errors += inb(ioaddr + 0);
- lp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- lp->stats.collisions += inb(ioaddr + 3);
- lp->stats.tx_window_errors += inb(ioaddr + 4);
- lp->stats.rx_fifo_errors += inb(ioaddr + 5);
- lp->stats.tx_packets += inb(ioaddr + 6);
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
/* Rx packets */ inb(ioaddr + 7);
/* Tx deferrals */ inb(ioaddr + 8);
inw(ioaddr + 10); /* Total Rx and Tx octets. */
@@ -1042,7 +1038,6 @@ static void update_stats(struct net_device *dev)
static int
el3_rx(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
short rx_status;
@@ -1054,21 +1049,21 @@ el3_rx(struct net_device *dev)
short error = rx_status & 0x3800;
outw(RxDiscard, ioaddr + EL3_CMD);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
switch (error) {
- case 0x0000: lp->stats.rx_over_errors++; break;
- case 0x0800: lp->stats.rx_length_errors++; break;
- case 0x1000: lp->stats.rx_frame_errors++; break;
- case 0x1800: lp->stats.rx_length_errors++; break;
- case 0x2000: lp->stats.rx_frame_errors++; break;
- case 0x2800: lp->stats.rx_crc_errors++; break;
+ case 0x0000: dev->stats.rx_over_errors++; break;
+ case 0x0800: dev->stats.rx_length_errors++; break;
+ case 0x1000: dev->stats.rx_frame_errors++; break;
+ case 0x1800: dev->stats.rx_length_errors++; break;
+ case 0x2000: dev->stats.rx_frame_errors++; break;
+ case 0x2800: dev->stats.rx_crc_errors++; break;
}
} else {
short pkt_len = rx_status & 0x7ff;
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1083,11 +1078,11 @@ el3_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
continue;
}
outw(RxDiscard, ioaddr + EL3_CMD);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
if (el3_debug)
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, pkt_len);
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 6ab84b661d70..105a8c7ca7e9 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -310,7 +310,6 @@ struct corkscrew_private {
struct sk_buff *tx_skbuff[TX_RING_SIZE];
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
- struct net_device_stats stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
struct timer_list timer; /* Media selection timer. */
int capabilities ; /* Adapter capabilities word. */
@@ -983,8 +982,8 @@ static void corkscrew_timeout(struct net_device *dev)
break;
outw(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies;
- vp->stats.tx_errors++;
- vp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1050,7 +1049,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
- vp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
@@ -1094,9 +1093,9 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
printk("%s: Tx error, status %2.2x.\n",
dev->name, tx_status);
if (tx_status & 0x04)
- vp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (tx_status & 0x38)
- vp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
@@ -1257,7 +1256,6 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
static int corkscrew_rx(struct net_device *dev)
{
- struct corkscrew_private *vp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int i;
short rx_status;
@@ -1271,17 +1269,17 @@ static int corkscrew_rx(struct net_device *dev)
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
- vp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_error & 0x01)
- vp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rx_error & 0x02)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_error & 0x04)
- vp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
- vp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
@@ -1301,8 +1299,8 @@ static int corkscrew_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
- vp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1312,7 +1310,7 @@ static int corkscrew_rx(struct net_device *dev)
printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
}
outw(RxDiscard, ioaddr + EL3_CMD);
- vp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
/* Wait a limited time to skip this packet. */
for (i = 200; i >= 0; i--)
if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1337,23 +1335,23 @@ static int boomerang_rx(struct net_device *dev)
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
- vp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_error & 0x01)
- vp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rx_error & 0x02)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_error & 0x04)
- vp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
- vp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
- vp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
if (corkscrew_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1388,7 +1386,7 @@ static int boomerang_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
@@ -1475,7 +1473,7 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
update_stats(dev->base_addr, dev);
spin_unlock_irqrestore(&vp->lock, flags);
}
- return &vp->stats;
+ return &dev->stats;
}
/* Update statistics.
@@ -1487,19 +1485,17 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
*/
static void update_stats(int ioaddr, struct net_device *dev)
{
- struct corkscrew_private *vp = netdev_priv(dev);
-
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- vp->stats.tx_carrier_errors += inb(ioaddr + 0);
- vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- vp->stats.collisions += inb(ioaddr + 3);
- vp->stats.tx_window_errors += inb(ioaddr + 4);
- vp->stats.rx_fifo_errors += inb(ioaddr + 5);
- vp->stats.tx_packets += inb(ioaddr + 6);
- vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
+ dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
/* Rx packets */ inb(ioaddr + 7);
/* Must read to clear */
/* Tx deferrals */ inb(ioaddr + 8);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 6f8e7d4cf74d..2edda8cc7f99 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -319,7 +319,7 @@ static struct vortex_chip_info {
{"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
{"3c980 Cyclone",
- PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
{"3c980C Python-T",
PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
@@ -600,7 +600,6 @@ struct vortex_private {
struct sk_buff* tx_skbuff[TX_RING_SIZE];
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- struct net_device_stats stats; /* Generic stats */
struct vortex_extra_stats xstats; /* NIC-specific extra stats */
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */
@@ -1875,7 +1874,7 @@ static void vortex_tx_timeout(struct net_device *dev)
issue_and_wait(dev, TxReset);
- vp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (vp->full_bus_master_tx) {
printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name);
if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) == 0)
@@ -1887,7 +1886,7 @@ static void vortex_tx_timeout(struct net_device *dev)
iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
iowrite16(DownUnstall, ioaddr + EL3_CMD);
} else {
- vp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1928,8 +1927,8 @@ vortex_error(struct net_device *dev, int status)
}
dump_tx_ring(dev);
}
- if (tx_status & 0x14) vp->stats.tx_fifo_errors++;
- if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
+ if (tx_status & 0x14) dev->stats.tx_fifo_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x08) vp->xstats.tx_max_collisions++;
iowrite8(0, ioaddr + TxStatus);
if (tx_status & 0x30) { /* txJabber or txUnderrun */
@@ -2051,8 +2050,8 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (vortex_debug > 2)
printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
dev->name, tx_status);
- if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
- if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
+ if (tx_status & 0x04) dev->stats.tx_fifo_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
issue_and_wait(dev, TxReset);
}
@@ -2350,7 +2349,7 @@ boomerang_interrupt(int irq, void *dev_id)
} else {
printk(KERN_DEBUG "boomerang_interrupt: no skb!\n");
}
- /* vp->stats.tx_packets++; Counted below. */
+ /* dev->stats.tx_packets++; Counted below. */
dirty_tx++;
}
vp->dirty_tx = dirty_tx;
@@ -2409,12 +2408,12 @@ static int vortex_rx(struct net_device *dev)
unsigned char rx_error = ioread8(ioaddr + RxErrors);
if (vortex_debug > 2)
printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
- vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
- if (rx_error & 0x10) vp->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ if (rx_error & 0x01) dev->stats.rx_over_errors++;
+ if (rx_error & 0x02) dev->stats.rx_length_errors++;
+ if (rx_error & 0x04) dev->stats.rx_frame_errors++;
+ if (rx_error & 0x08) dev->stats.rx_crc_errors++;
+ if (rx_error & 0x10) dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
int pkt_len = rx_status & 0x1fff;
@@ -2446,7 +2445,7 @@ static int vortex_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
+ dev->stats.rx_packets++;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
if ( ! (ioread16(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -2455,7 +2454,7 @@ static int vortex_rx(struct net_device *dev)
} else if (vortex_debug > 0)
printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
"size %d.\n", dev->name, pkt_len);
- vp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
issue_and_wait(dev, RxDiscard);
}
@@ -2482,12 +2481,12 @@ boomerang_rx(struct net_device *dev)
unsigned char rx_error = rx_status >> 16;
if (vortex_debug > 2)
printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
- vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
- if (rx_error & 0x10) vp->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ if (rx_error & 0x01) dev->stats.rx_over_errors++;
+ if (rx_error & 0x02) dev->stats.rx_length_errors++;
+ if (rx_error & 0x04) dev->stats.rx_frame_errors++;
+ if (rx_error & 0x08) dev->stats.rx_crc_errors++;
+ if (rx_error & 0x10) dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
int pkt_len = rx_status & 0x1fff;
@@ -2529,7 +2528,7 @@ boomerang_rx(struct net_device *dev)
}
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
@@ -2591,7 +2590,7 @@ vortex_down(struct net_device *dev, int final_down)
del_timer_sync(&vp->rx_oom_timer);
del_timer_sync(&vp->timer);
- /* Turn off statistics ASAP. We update vp->stats below. */
+ /* Turn off statistics ASAP. We update dev->stats below. */
iowrite16(StatsDisable, ioaddr + EL3_CMD);
/* Disable the receiver and transmitter. */
@@ -2728,7 +2727,7 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev)
update_stats(ioaddr, dev);
spin_unlock_irqrestore (&vp->lock, flags);
}
- return &vp->stats;
+ return &dev->stats;
}
/* Update statistics.
@@ -2748,18 +2747,18 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- vp->stats.tx_carrier_errors += ioread8(ioaddr + 0);
- vp->stats.tx_heartbeat_errors += ioread8(ioaddr + 1);
- vp->stats.tx_window_errors += ioread8(ioaddr + 4);
- vp->stats.rx_fifo_errors += ioread8(ioaddr + 5);
- vp->stats.tx_packets += ioread8(ioaddr + 6);
- vp->stats.tx_packets += (ioread8(ioaddr + 9)&0x30) << 4;
+ dev->stats.tx_carrier_errors += ioread8(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += ioread8(ioaddr + 1);
+ dev->stats.tx_window_errors += ioread8(ioaddr + 4);
+ dev->stats.rx_fifo_errors += ioread8(ioaddr + 5);
+ dev->stats.tx_packets += ioread8(ioaddr + 6);
+ dev->stats.tx_packets += (ioread8(ioaddr + 9)&0x30) << 4;
/* Rx packets */ ioread8(ioaddr + 7); /* Must read to clear */
/* Don't bother with register 9, an extension of registers 6&7.
If we do use the 6&7 values the atomic update assumption above
is invalid. */
- vp->stats.rx_bytes += ioread16(ioaddr + 10);
- vp->stats.tx_bytes += ioread16(ioaddr + 12);
+ dev->stats.rx_bytes += ioread16(ioaddr + 10);
+ dev->stats.tx_bytes += ioread16(ioaddr + 12);
/* Extra stats for get_ethtool_stats() */
vp->xstats.tx_multiple_collisions += ioread8(ioaddr + 2);
vp->xstats.tx_single_collisions += ioread8(ioaddr + 3);
@@ -2767,14 +2766,14 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
EL3WINDOW(4);
vp->xstats.rx_bad_ssd += ioread8(ioaddr + 12);
- vp->stats.collisions = vp->xstats.tx_multiple_collisions
+ dev->stats.collisions = vp->xstats.tx_multiple_collisions
+ vp->xstats.tx_single_collisions
+ vp->xstats.tx_max_collisions;
{
u8 up = ioread8(ioaddr + 13);
- vp->stats.rx_bytes += (up & 0x0f) << 16;
- vp->stats.tx_bytes += (up & 0xf0) << 12;
+ dev->stats.rx_bytes += (up & 0x0f) << 16;
+ dev->stats.tx_bytes += (up & 0xf0) << 12;
}
EL3WINDOW(old_window >> 13);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 2797da7eeee6..da292e647eb1 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1162,6 +1162,7 @@ struct net_device * __init i82596_probe(int unit)
memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */
dev->base_addr = MVME_I596_BASE;
dev->irq = (unsigned) MVME16x_IRQ_I596;
+ goto found;
}
#endif
#ifdef ENABLE_BVME6000_NET
@@ -1176,6 +1177,7 @@ struct net_device * __init i82596_probe(int unit)
rtc[3] = msr;
dev->base_addr = BVME_I596_BASE;
dev->irq = (unsigned) BVME_IRQ_I596;
+ goto found;
}
#endif
#ifdef ENABLE_APRICOT
@@ -1212,8 +1214,13 @@ struct net_device * __init i82596_probe(int unit)
}
dev->irq = 10;
+ goto found;
}
#endif
+ err = -ENODEV;
+ goto out;
+
+found:
dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
if (!dev->mem_start) {
err = -ENOMEM;
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index a499e867f0f4..dc5d2584bd0c 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -34,7 +34,7 @@ struct net_device *__alloc_ei_netdev(int size)
void NS8390_init(struct net_device *dev, int startp)
{
- return __NS8390_init(dev, startp);
+ __NS8390_init(dev, startp);
}
EXPORT_SYMBOL(ei_open);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f90a86ba7e2f..9f6cc8a56073 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1273,20 +1273,6 @@ config PCNET32
To compile this driver as a module, choose M here. The module
will be called pcnet32.
-config PCNET32_NAPI
- 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
- still somewhat experimental and thus not yet enabled by default.
-
- If your estimated Rx load is 10kpps or more, or if the card will be
- deployed on potentially unfriendly networks (e.g. in a firewall),
- then say Y here.
-
- If in doubt, say N.
-
config AMD8111_ETH
tristate "AMD 8111 (new PCI lance) support"
depends on NET_PCI && PCI
@@ -2440,7 +2426,7 @@ config CHELSIO_T3
config EHEA
tristate "eHEA Ethernet support"
- depends on IBMEBUS && INET && SPARSEMEM
+ depends on IBMEBUS && INET && SPARSEMEM && MEMORY_HOTPLUG
select INET_LRO
---help---
This driver supports the IBM pSeries eHEA ethernet adapter.
@@ -2593,6 +2579,7 @@ config BNX2X
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
+source "drivers/net/sfc/Kconfig"
endif # NETDEV_10000
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 2f1f3f2739fd..dcbfe8421154 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -253,3 +253,5 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+obj-$(CONFIG_SFC) += sfc/
+
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index 47a8275d3962..867f6fff543c 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -127,6 +127,9 @@ struct net_device * __init apne_probe(int unit)
#endif
int err;
+ if (!MACH_IS_AMIGA)
+ return ERR_PTR(-ENODEV);
+
if (apne_owned)
return ERR_PTR(-ENODEV);
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 82e9a5bd0dd2..a0b4c8516073 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -499,19 +499,13 @@ static void cops_reset(struct net_device *dev, int sleep)
{
outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */
inb(ioaddr+DAYNA_RESET); /* Clear the reset */
- if(sleep)
- {
- long snap=jiffies;
-
- /* Let card finish initializing, about 1/3 second */
- while (time_before(jiffies, snap + HZ/3))
- schedule();
- }
- else
- mdelay(333);
+ if (sleep)
+ msleep(333);
+ else
+ mdelay(333);
}
+
netif_wake_queue(dev);
- return;
}
static void cops_load (struct net_device *dev)
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index f9cc2b621fe2..8eda6eeb43b7 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -47,3 +47,11 @@ config EP93XX_ETH
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices.
+
+config IXP4XX_ETH
+ tristate "Intel IXP4xx Ethernet support"
+ depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+ select MII
+ help
+ Say Y here if you want to use built-in Ethernet ports
+ on IXP4xx processor.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
index a4c868278e11..7c812ac2b6a5 100644
--- a/drivers/net/arm/Makefile
+++ b/drivers/net/arm/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_ARM_ETHER3) += ether3.o
obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
+obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index ba6bd03a015f..a637910b02dd 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -693,11 +693,15 @@ static int __init am79c961_probe(struct platform_device *pdev)
* done by the ether bootp loader.
*/
dev->base_addr = res->start;
- dev->irq = platform_get_irq(pdev, 0);
+ ret = platform_get_irq(pdev, 0);
- ret = -ENODEV;
- if (dev->irq < 0)
+ if (ret < 0) {
+ ret = -ENODEV;
goto nodev;
+ }
+ dev->irq = ret;
+
+ ret = -ENODEV;
if (!request_region(dev->base_addr, 0x18, dev->name))
goto nodev;
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
new file mode 100644
index 000000000000..c617b64c288e
--- /dev/null
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -0,0 +1,1265 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 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.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port 0x00 0x10 0x20
+ * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
+ * physical PortId 2 0 1
+ * TX queue 23 24 25
+ * RX-free queue 26 27 28
+ * TX-done queue is always 31, per-port RX and TX-ready queues are configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1 - NPE ID (RX and TX-done)
+ * bits 0 -> 2 - priority (TX, per 802.1D)
+ * bits 3 -> 4 - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/etherdevice.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/platform_device.h>
+#include <asm/arch/npe.h>
+#include <asm/arch/qmgr.h>
+
+#define DEBUG_QUEUES 0
+#define DEBUG_DESC 0
+#define DEBUG_RX 0
+#define DEBUG_TX 0
+#define DEBUG_PKT_BYTES 0
+#define DEBUG_MDIO 0
+#define DEBUG_CLOSE 0
+
+#define DRV_NAME "ixp4xx_eth"
+
+#define MAX_NPES 3
+
+#define RX_DESCS 64 /* also length of all RX queues */
+#define TX_DESCS 16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN 64 /* dwords */
+
+#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
+#define REGS_SIZE 0x1000
+#define MAX_MRU 1536 /* 0x600 */
+#define RX_BUFF_SIZE ALIGN((NET_IP_ALIGN) + MAX_MRU, 4)
+
+#define NAPI_WEIGHT 16
+#define MDIO_INTERVAL (3 * HZ)
+#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
+#define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */
+#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
+
+#define NPE_ID(port_id) ((port_id) >> 4)
+#define PHYSICAL_ID(port_id) ((NPE_ID(port_id) + 2) % 3)
+#define TX_QUEUE(port_id) (NPE_ID(port_id) + 23)
+#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
+#define TXDONE_QUEUE 31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN 0x01
+#define TX_CNTRL0_HALFDUPLEX 0x02
+#define TX_CNTRL0_RETRY 0x04
+#define TX_CNTRL0_PAD_EN 0x08
+#define TX_CNTRL0_APPEND_FCS 0x10
+#define TX_CNTRL0_2DEFER 0x20
+#define TX_CNTRL0_RMII 0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN 0x01
+#define RX_CNTRL0_PADSTRIP_EN 0x02
+#define RX_CNTRL0_SEND_FCS 0x04
+#define RX_CNTRL0_PAUSE_EN 0x08
+#define RX_CNTRL0_LOOP_EN 0x10
+#define RX_CNTRL0_ADDR_FLTR_EN 0x20
+#define RX_CNTRL0_RX_RUNT_EN 0x40
+#define RX_CNTRL0_BCAST_DIS 0x80
+#define RX_CNTRL1_DEFER_EN 0x01
+
+/* Core Control Register */
+#define CORE_RESET 0x01
+#define CORE_RX_FIFO_FLUSH 0x02
+#define CORE_TX_FIFO_FLUSH 0x04
+#define CORE_SEND_JAM 0x08
+#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
+ TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+ TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS 0x00
+#define NPE_EDB_SETPORTADDRESS 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
+#define NPE_GETSTATS 0x04
+#define NPE_RESETSTATS 0x05
+#define NPE_SETMAXFRAMELENGTHS 0x06
+#define NPE_VLAN_SETRXTAGMODE 0x07
+#define NPE_VLAN_SETDEFAULTRXVID 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
+#define NPE_VLAN_SETRXQOSENTRY 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE 0x0D
+#define NPE_FW_SETFIREWALLMODE 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE 0x11
+#define NPE_SETLOOPBACK_MODE 0x12
+#define NPE_PC_SETBSSIDTABLE 0x13
+#define NPE_ADDRESS_FILTER_CONFIG 0x14
+#define NPE_APPENDFCSCONFIG 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
+#define NPE_MAC_RECOVERY_START 0x17
+
+
+#ifdef __ARMEB__
+typedef struct sk_buff buffer_t;
+#define free_buffer dev_kfree_skb
+#define free_buffer_irq dev_kfree_skb_irq
+#else
+typedef void buffer_t;
+#define free_buffer kfree
+#define free_buffer_irq kfree
+#endif
+
+struct eth_regs {
+ u32 tx_control[2], __res1[2]; /* 000 */
+ u32 rx_control[2], __res2[2]; /* 010 */
+ u32 random_seed, __res3[3]; /* 020 */
+ u32 partial_empty_threshold, __res4; /* 030 */
+ u32 partial_full_threshold, __res5; /* 038 */
+ u32 tx_start_bytes, __res6[3]; /* 040 */
+ u32 tx_deferral, rx_deferral, __res7[2];/* 050 */
+ u32 tx_2part_deferral[2], __res8[2]; /* 060 */
+ u32 slot_time, __res9[3]; /* 070 */
+ u32 mdio_command[4]; /* 080 */
+ u32 mdio_status[4]; /* 090 */
+ u32 mcast_mask[6], __res10[2]; /* 0A0 */
+ u32 mcast_addr[6], __res11[2]; /* 0C0 */
+ u32 int_clock_threshold, __res12[3]; /* 0E0 */
+ u32 hw_addr[6], __res13[61]; /* 0F0 */
+ u32 core_control; /* 1FC */
+};
+
+struct port {
+ struct resource *mem_res;
+ struct eth_regs __iomem *regs;
+ struct npe *npe;
+ struct net_device *netdev;
+ struct napi_struct napi;
+ struct net_device_stats stat;
+ struct mii_if_info mii;
+ struct delayed_work mdio_thread;
+ struct eth_plat_info *plat;
+ buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
+ struct desc *desc_tab; /* coherent */
+ u32 desc_tab_phys;
+ int id; /* logical port ID */
+ u16 mii_bmcr;
+};
+
+/* NPE message structure */
+struct msg {
+#ifdef __ARMEB__
+ u8 cmd, eth_id, byte2, byte3;
+ u8 byte4, byte5, byte6, byte7;
+#else
+ u8 byte3, byte2, eth_id, cmd;
+ u8 byte7, byte6, byte5, byte4;
+#endif
+};
+
+/* Ethernet packet descriptor */
+struct desc {
+ u32 next; /* pointer to next buffer, unused */
+
+#ifdef __ARMEB__
+ u16 buf_len; /* buffer length */
+ u16 pkt_len; /* packet length */
+ u32 data; /* pointer to data buffer in RAM */
+ u8 dest_id;
+ u8 src_id;
+ u16 flags;
+ u8 qos;
+ u8 padlen;
+ u16 vlan_tci;
+#else
+ u16 pkt_len; /* packet length */
+ u16 buf_len; /* buffer length */
+ u32 data; /* pointer to data buffer in RAM */
+ u16 flags;
+ u8 src_id;
+ u8 dest_id;
+ u16 vlan_tci;
+ u8 padlen;
+ u8 qos;
+#endif
+
+#ifdef __ARMEB__
+ u8 dst_mac_0, dst_mac_1, dst_mac_2, dst_mac_3;
+ u8 dst_mac_4, dst_mac_5, src_mac_0, src_mac_1;
+ u8 src_mac_2, src_mac_3, src_mac_4, src_mac_5;
+#else
+ u8 dst_mac_3, dst_mac_2, dst_mac_1, dst_mac_0;
+ u8 src_mac_1, src_mac_0, dst_mac_5, dst_mac_4;
+ u8 src_mac_5, src_mac_4, src_mac_3, src_mac_2;
+#endif
+};
+
+
+#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
+ (n) * sizeof(struct desc))
+#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
+
+#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
+ ((n) + RX_DESCS) * sizeof(struct desc))
+#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
+
+#ifndef __ARMEB__
+static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
+{
+ int i;
+ for (i = 0; i < cnt; i++)
+ dest[i] = swab32(src[i]);
+}
+#endif
+
+static spinlock_t mdio_lock;
+static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
+static int ports_open;
+static struct port *npe_port_tab[MAX_NPES];
+static struct dma_pool *dma_pool;
+
+
+static u16 mdio_cmd(struct net_device *dev, int phy_id, int location,
+ int write, u16 cmd)
+{
+ int cycles = 0;
+
+ if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+ printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name);
+ return 0;
+ }
+
+ if (write) {
+ __raw_writel(cmd & 0xFF, &mdio_regs->mdio_command[0]);
+ __raw_writel(cmd >> 8, &mdio_regs->mdio_command[1]);
+ }
+ __raw_writel(((phy_id << 5) | location) & 0xFF,
+ &mdio_regs->mdio_command[2]);
+ __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+ &mdio_regs->mdio_command[3]);
+
+ while ((cycles < MAX_MDIO_RETRIES) &&
+ (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_MDIO_RETRIES) {
+ printk(KERN_ERR "%s: MII write failed\n", dev->name);
+ return 0;
+ }
+
+#if DEBUG_MDIO
+ printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name,
+ cycles);
+#endif
+
+ if (write)
+ return 0;
+
+ if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+ printk(KERN_ERR "%s: MII read failed\n", dev->name);
+ return 0;
+ }
+
+ return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+ (__raw_readl(&mdio_regs->mdio_status[1]) << 8);
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ unsigned long flags;
+ u16 val;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ val = mdio_cmd(dev, phy_id, location, 0, 0);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ return val;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+ int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ mdio_cmd(dev, phy_id, location, 1, val);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+}
+
+static void phy_reset(struct net_device *dev, int phy_id)
+{
+ struct port *port = netdev_priv(dev);
+ int cycles = 0;
+
+ mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);
+
+ while (cycles < MAX_MII_RESET_RETRIES) {
+ if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
+#if DEBUG_MDIO
+ printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n",
+ dev->name, cycles);
+#endif
+ return;
+ }
+ udelay(1);
+ cycles++;
+ }
+
+ printk(KERN_ERR "%s: MII reset failed\n", dev->name);
+}
+
+static void eth_set_duplex(struct port *port)
+{
+ if (port->mii.full_duplex)
+ __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+ else
+ __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+}
+
+
+static void phy_check_media(struct port *port, int init)
+{
+ if (mii_check_media(&port->mii, 1, init))
+ eth_set_duplex(port);
+ if (port->mii.force_media) { /* mii_check_media() doesn't work */
+ struct net_device *dev = port->netdev;
+ int cur_link = mii_link_ok(&port->mii);
+ int prev_link = netif_carrier_ok(dev);
+
+ if (!prev_link && cur_link) {
+ printk(KERN_INFO "%s: link up\n", dev->name);
+ netif_carrier_on(dev);
+ } else if (prev_link && !cur_link) {
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ netif_carrier_off(dev);
+ }
+ }
+}
+
+
+static void mdio_thread(struct work_struct *work)
+{
+ struct port *port = container_of(work, struct port, mdio_thread.work);
+
+ phy_check_media(port, 0);
+ schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+}
+
+
+static inline void debug_pkt(struct net_device *dev, const char *func,
+ u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+ int i;
+
+ printk(KERN_DEBUG "%s: %s(%i) ", dev->name, func, len);
+ for (i = 0; i < len; i++) {
+ if (i >= DEBUG_PKT_BYTES)
+ break;
+ printk("%s%02X",
+ ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+ data[i]);
+ }
+ printk("\n");
+#endif
+}
+
+
+static inline void debug_desc(u32 phys, struct desc *desc)
+{
+#if DEBUG_DESC
+ printk(KERN_DEBUG "%X: %X %3X %3X %08X %2X < %2X %4X %X"
+ " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+ phys, desc->next, desc->buf_len, desc->pkt_len,
+ desc->data, desc->dest_id, desc->src_id, desc->flags,
+ desc->qos, desc->padlen, desc->vlan_tci,
+ desc->dst_mac_0, desc->dst_mac_1, desc->dst_mac_2,
+ desc->dst_mac_3, desc->dst_mac_4, desc->dst_mac_5,
+ desc->src_mac_0, desc->src_mac_1, desc->src_mac_2,
+ desc->src_mac_3, desc->src_mac_4, desc->src_mac_5);
+#endif
+}
+
+static inline void debug_queue(unsigned int queue, int is_get, u32 phys)
+{
+#if DEBUG_QUEUES
+ static struct {
+ int queue;
+ char *name;
+ } names[] = {
+ { TX_QUEUE(0x10), "TX#0 " },
+ { TX_QUEUE(0x20), "TX#1 " },
+ { TX_QUEUE(0x00), "TX#2 " },
+ { RXFREE_QUEUE(0x10), "RX-free#0 " },
+ { RXFREE_QUEUE(0x20), "RX-free#1 " },
+ { RXFREE_QUEUE(0x00), "RX-free#2 " },
+ { TXDONE_QUEUE, "TX-done " },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(names); i++)
+ if (names[i].queue == queue)
+ break;
+
+ printk(KERN_DEBUG "Queue %i %s%s %X\n", queue,
+ i < ARRAY_SIZE(names) ? names[i].name : "",
+ is_get ? "->" : "<-", phys);
+#endif
+}
+
+static inline u32 queue_get_entry(unsigned int queue)
+{
+ u32 phys = qmgr_get_entry(queue);
+ debug_queue(queue, 1, phys);
+ return phys;
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+ int is_tx)
+{
+ u32 phys, tab_phys, n_desc;
+ struct desc *tab;
+
+ if (!(phys = queue_get_entry(queue)))
+ return -1;
+
+ phys &= ~0x1F; /* mask out non-address bits */
+ tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0);
+ tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0);
+ n_desc = (phys - tab_phys) / sizeof(struct desc);
+ BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS));
+ debug_desc(phys, &tab[n_desc]);
+ BUG_ON(tab[n_desc].next);
+ return n_desc;
+}
+
+static inline void queue_put_desc(unsigned int queue, u32 phys,
+ struct desc *desc)
+{
+ debug_queue(queue, 0, phys);
+ debug_desc(phys, desc);
+ BUG_ON(phys & 0x1F);
+ qmgr_put_entry(queue, phys);
+ BUG_ON(qmgr_stat_overflow(queue));
+}
+
+
+static inline void dma_unmap_tx(struct port *port, struct desc *desc)
+{
+#ifdef __ARMEB__
+ dma_unmap_single(&port->netdev->dev, desc->data,
+ desc->buf_len, DMA_TO_DEVICE);
+#else
+ dma_unmap_single(&port->netdev->dev, desc->data & ~3,
+ ALIGN((desc->data & 3) + desc->buf_len, 4),
+ DMA_TO_DEVICE);
+#endif
+}
+
+
+static void eth_rx_irq(void *pdev)
+{
+ struct net_device *dev = pdev;
+ struct port *port = netdev_priv(dev);
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name);
+#endif
+ qmgr_disable_irq(port->plat->rxq);
+ netif_rx_schedule(dev, &port->napi);
+}
+
+static int eth_poll(struct napi_struct *napi, int budget)
+{
+ struct port *port = container_of(napi, struct port, napi);
+ struct net_device *dev = port->netdev;
+ unsigned int rxq = port->plat->rxq, rxfreeq = RXFREE_QUEUE(port->id);
+ int received = 0;
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll\n", dev->name);
+#endif
+
+ while (received < budget) {
+ struct sk_buff *skb;
+ struct desc *desc;
+ int n;
+#ifdef __ARMEB__
+ struct sk_buff *temp;
+ u32 phys;
+#endif
+
+ if ((n = queue_get_desc(rxq, port, 0)) < 0) {
+ received = 0; /* No packet received */
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n",
+ dev->name);
+#endif
+ netif_rx_complete(dev, napi);
+ qmgr_enable_irq(rxq);
+ if (!qmgr_stat_empty(rxq) &&
+ netif_rx_reschedule(dev, napi)) {
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll"
+ " netif_rx_reschedule successed\n",
+ dev->name);
+#endif
+ qmgr_disable_irq(rxq);
+ continue;
+ }
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll all done\n",
+ dev->name);
+#endif
+ return 0; /* all work done */
+ }
+
+ desc = rx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+ if ((skb = netdev_alloc_skb(dev, RX_BUFF_SIZE))) {
+ phys = dma_map_single(&dev->dev, skb->data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(phys)) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+#else
+ skb = netdev_alloc_skb(dev,
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4));
+#endif
+
+ if (!skb) {
+ port->stat.rx_dropped++;
+ /* put the desc back on RX-ready queue */
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+ continue;
+ }
+
+ /* process received frame */
+#ifdef __ARMEB__
+ temp = skb;
+ skb = port->rx_buff_tab[n];
+ dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+#else
+ dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4);
+#endif
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, desc->pkt_len);
+
+ debug_pkt(dev, "eth_poll", skb->data, skb->len);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+ port->stat.rx_packets++;
+ port->stat.rx_bytes += skb->len;
+ netif_receive_skb(skb);
+
+ /* put the new buffer on RX-free queue */
+#ifdef __ARMEB__
+ port->rx_buff_tab[n] = temp;
+ desc->data = phys + NET_IP_ALIGN;
+#endif
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+ received++;
+ }
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "eth_poll(): end, not all work done\n");
+#endif
+ return received; /* not all work done */
+}
+
+
+static void eth_txdone_irq(void *unused)
+{
+ u32 phys;
+
+#if DEBUG_TX
+ printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n");
+#endif
+ while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) {
+ u32 npe_id, n_desc;
+ struct port *port;
+ struct desc *desc;
+ int start;
+
+ npe_id = phys & 3;
+ BUG_ON(npe_id >= MAX_NPES);
+ port = npe_port_tab[npe_id];
+ BUG_ON(!port);
+ phys &= ~0x1F; /* mask out non-address bits */
+ n_desc = (phys - tx_desc_phys(port, 0)) / sizeof(struct desc);
+ BUG_ON(n_desc >= TX_DESCS);
+ desc = tx_desc_ptr(port, n_desc);
+ debug_desc(phys, desc);
+
+ if (port->tx_buff_tab[n_desc]) { /* not the draining packet */
+ port->stat.tx_packets++;
+ port->stat.tx_bytes += desc->pkt_len;
+
+ dma_unmap_tx(port, desc);
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_txdone_irq free %p\n",
+ port->netdev->name, port->tx_buff_tab[n_desc]);
+#endif
+ free_buffer_irq(port->tx_buff_tab[n_desc]);
+ port->tx_buff_tab[n_desc] = NULL;
+ }
+
+ start = qmgr_stat_empty(port->plat->txreadyq);
+ queue_put_desc(port->plat->txreadyq, phys, desc);
+ if (start) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n",
+ port->netdev->name);
+#endif
+ netif_wake_queue(port->netdev);
+ }
+ }
+}
+
+static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ unsigned int txreadyq = port->plat->txreadyq;
+ int len, offset, bytes, n;
+ void *mem;
+ u32 phys;
+ struct desc *desc;
+
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit\n", dev->name);
+#endif
+
+ if (unlikely(skb->len > MAX_MRU)) {
+ dev_kfree_skb(skb);
+ port->stat.tx_errors++;
+ return NETDEV_TX_OK;
+ }
+
+ debug_pkt(dev, "eth_xmit", skb->data, skb->len);
+
+ len = skb->len;
+#ifdef __ARMEB__
+ offset = 0; /* no need to keep alignment */
+ bytes = len;
+ mem = skb->data;
+#else
+ offset = (int)skb->data & 3; /* keep 32-bit alignment */
+ bytes = ALIGN(offset + len, 4);
+ if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
+ dev_kfree_skb(skb);
+ port->stat.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+ memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
+ dev_kfree_skb(skb);
+#endif
+
+ phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(phys)) {
+#ifdef __ARMEB__
+ dev_kfree_skb(skb);
+#else
+ kfree(mem);
+#endif
+ port->stat.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ n = queue_get_desc(txreadyq, port, 1);
+ BUG_ON(n < 0);
+ desc = tx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+ port->tx_buff_tab[n] = skb;
+#else
+ port->tx_buff_tab[n] = mem;
+#endif
+ desc->data = phys + offset;
+ desc->buf_len = desc->pkt_len = len;
+
+ /* NPE firmware pads short frames with zeros internally */
+ wmb();
+ queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
+ dev->trans_start = jiffies;
+
+ if (qmgr_stat_empty(txreadyq)) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name);
+#endif
+ netif_stop_queue(dev);
+ /* we could miss TX ready interrupt */
+ if (!qmgr_stat_empty(txreadyq)) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit ready again\n",
+ dev->name);
+#endif
+ netif_wake_queue(dev);
+ }
+ }
+
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
+#endif
+ return NETDEV_TX_OK;
+}
+
+
+static struct net_device_stats *eth_stats(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ return &port->stat;
+}
+
+static void eth_set_mcast_list(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct dev_mc_list *mclist = dev->mc_list;
+ u8 diffs[ETH_ALEN], *addr;
+ int cnt = dev->mc_count, i;
+
+ if ((dev->flags & IFF_PROMISC) || !mclist || !cnt) {
+ __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+ return;
+ }
+
+ memset(diffs, 0, ETH_ALEN);
+ addr = mclist->dmi_addr; /* first MAC address */
+
+ while (--cnt && (mclist = mclist->next))
+ for (i = 0; i < ETH_ALEN; i++)
+ diffs[i] |= addr[i] ^ mclist->dmi_addr[i];
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ __raw_writel(addr[i], &port->regs->mcast_addr[i]);
+ __raw_writel(~diffs[i], &port->regs->mcast_mask[i]);
+ }
+
+ __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+}
+
+
+static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ struct port *port = netdev_priv(dev);
+ unsigned int duplex_chg;
+ int err;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+ err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
+ if (duplex_chg)
+ eth_set_duplex(port);
+ return err;
+}
+
+
+static int request_queues(struct port *port)
+{
+ int err;
+
+ err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0);
+ if (err)
+ return err;
+
+ err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0);
+ if (err)
+ goto rel_rxfree;
+
+ err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0);
+ if (err)
+ goto rel_rx;
+
+ err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0);
+ if (err)
+ goto rel_tx;
+
+ /* TX-done queue handles skbs sent out by the NPEs */
+ if (!ports_open) {
+ err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0);
+ if (err)
+ goto rel_txready;
+ }
+ return 0;
+
+rel_txready:
+ qmgr_release_queue(port->plat->txreadyq);
+rel_tx:
+ qmgr_release_queue(TX_QUEUE(port->id));
+rel_rx:
+ qmgr_release_queue(port->plat->rxq);
+rel_rxfree:
+ qmgr_release_queue(RXFREE_QUEUE(port->id));
+ printk(KERN_DEBUG "%s: unable to request hardware queues\n",
+ port->netdev->name);
+ return err;
+}
+
+static void release_queues(struct port *port)
+{
+ qmgr_release_queue(RXFREE_QUEUE(port->id));
+ qmgr_release_queue(port->plat->rxq);
+ qmgr_release_queue(TX_QUEUE(port->id));
+ qmgr_release_queue(port->plat->txreadyq);
+
+ if (!ports_open)
+ qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static int init_queues(struct port *port)
+{
+ int i;
+
+ if (!ports_open)
+ if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
+ POOL_ALLOC_SIZE, 32, 0)))
+ return -ENOMEM;
+
+ if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
+ &port->desc_tab_phys)))
+ return -ENOMEM;
+ memset(port->desc_tab, 0, POOL_ALLOC_SIZE);
+ memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */
+ memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab));
+
+ /* Setup RX buffers */
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff; /* skb or kmalloc()ated memory */
+ void *data;
+#ifdef __ARMEB__
+ if (!(buff = netdev_alloc_skb(port->netdev, RX_BUFF_SIZE)))
+ return -ENOMEM;
+ data = buff->data;
+#else
+ if (!(buff = kmalloc(RX_BUFF_SIZE, GFP_KERNEL)))
+ return -ENOMEM;
+ data = buff;
+#endif
+ desc->buf_len = MAX_MRU;
+ desc->data = dma_map_single(&port->netdev->dev, data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(desc->data)) {
+ free_buffer(buff);
+ return -EIO;
+ }
+ desc->data += NET_IP_ALIGN;
+ port->rx_buff_tab[i] = buff;
+ }
+
+ return 0;
+}
+
+static void destroy_queues(struct port *port)
+{
+ int i;
+
+ if (port->desc_tab) {
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff = port->rx_buff_tab[i];
+ if (buff) {
+ dma_unmap_single(&port->netdev->dev,
+ desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ free_buffer(buff);
+ }
+ }
+ for (i = 0; i < TX_DESCS; i++) {
+ struct desc *desc = tx_desc_ptr(port, i);
+ buffer_t *buff = port->tx_buff_tab[i];
+ if (buff) {
+ dma_unmap_tx(port, desc);
+ free_buffer(buff);
+ }
+ }
+ dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys);
+ port->desc_tab = NULL;
+ }
+
+ if (!ports_open && dma_pool) {
+ dma_pool_destroy(dma_pool);
+ dma_pool = NULL;
+ }
+}
+
+static int eth_open(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct npe *npe = port->npe;
+ struct msg msg;
+ int i, err;
+
+ if (!npe_running(npe)) {
+ err = npe_load_firmware(npe, npe_name(npe), &dev->dev);
+ if (err)
+ return err;
+
+ if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+ printk(KERN_ERR "%s: %s not responding\n", dev->name,
+ npe_name(npe));
+ return -EIO;
+ }
+ }
+
+ mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+ msg.eth_id = port->id;
+ msg.byte5 = port->plat->rxq | 0x80;
+ msg.byte7 = port->plat->rxq << 4;
+ for (i = 0; i < 8; i++) {
+ msg.byte3 = i;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ"))
+ return -EIO;
+ }
+
+ msg.cmd = NPE_EDB_SETPORTADDRESS;
+ msg.eth_id = PHYSICAL_ID(port->id);
+ msg.byte2 = dev->dev_addr[0];
+ msg.byte3 = dev->dev_addr[1];
+ msg.byte4 = dev->dev_addr[2];
+ msg.byte5 = dev->dev_addr[3];
+ msg.byte6 = dev->dev_addr[4];
+ msg.byte7 = dev->dev_addr[5];
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC"))
+ return -EIO;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_FW_SETFIREWALLMODE;
+ msg.eth_id = port->id;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE"))
+ return -EIO;
+
+ if ((err = request_queues(port)) != 0)
+ return err;
+
+ if ((err = init_queues(port)) != 0) {
+ destroy_queues(port);
+ release_queues(port);
+ return err;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
+ __raw_writel(0x08, &port->regs->random_seed);
+ __raw_writel(0x12, &port->regs->partial_empty_threshold);
+ __raw_writel(0x30, &port->regs->partial_full_threshold);
+ __raw_writel(0x08, &port->regs->tx_start_bytes);
+ __raw_writel(0x15, &port->regs->tx_deferral);
+ __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+ __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+ __raw_writel(0x80, &port->regs->slot_time);
+ __raw_writel(0x01, &port->regs->int_clock_threshold);
+
+ /* Populate queues with buffers, no failure after this point */
+ for (i = 0; i < TX_DESCS; i++)
+ queue_put_desc(port->plat->txreadyq,
+ tx_desc_phys(port, i), tx_desc_ptr(port, i));
+
+ for (i = 0; i < RX_DESCS; i++)
+ queue_put_desc(RXFREE_QUEUE(port->id),
+ rx_desc_phys(port, i), rx_desc_ptr(port, i));
+
+ __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+ __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+ __raw_writel(0, &port->regs->rx_control[1]);
+ __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+ napi_enable(&port->napi);
+ phy_check_media(port, 1);
+ eth_set_mcast_list(dev);
+ netif_start_queue(dev);
+ schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+
+ qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_rx_irq, dev);
+ if (!ports_open) {
+ qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_txdone_irq, NULL);
+ qmgr_enable_irq(TXDONE_QUEUE);
+ }
+ ports_open++;
+ /* we may already have RX data, enables IRQ */
+ netif_rx_schedule(dev, &port->napi);
+ return 0;
+}
+
+static int eth_close(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct msg msg;
+ int buffs = RX_DESCS; /* allocated RX buffers */
+ int i;
+
+ ports_open--;
+ qmgr_disable_irq(port->plat->rxq);
+ napi_disable(&port->napi);
+ netif_stop_queue(dev);
+
+ while (queue_get_desc(RXFREE_QUEUE(port->id), port, 0) >= 0)
+ buffs--;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_SETLOOPBACK_MODE;
+ msg.eth_id = port->id;
+ msg.byte3 = 1;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+ printk(KERN_CRIT "%s: unable to enable loopback\n", dev->name);
+
+ i = 0;
+ do { /* drain RX buffers */
+ while (queue_get_desc(port->plat->rxq, port, 0) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ if (qmgr_stat_empty(TX_QUEUE(port->id))) {
+ /* we have to inject some packet */
+ struct desc *desc;
+ u32 phys;
+ int n = queue_get_desc(port->plat->txreadyq, port, 1);
+ BUG_ON(n < 0);
+ desc = tx_desc_ptr(port, n);
+ phys = tx_desc_phys(port, n);
+ desc->buf_len = desc->pkt_len = 1;
+ wmb();
+ queue_put_desc(TX_QUEUE(port->id), phys, desc);
+ }
+ udelay(1);
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)"
+ " left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ printk(KERN_DEBUG "Draining RX queue took %i cycles\n", i);
+#endif
+
+ buffs = TX_DESCS;
+ while (queue_get_desc(TX_QUEUE(port->id), port, 1) >= 0)
+ buffs--; /* cancel TX */
+
+ i = 0;
+ do {
+ while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) "
+ "left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i);
+#endif
+
+ msg.byte3 = 0;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+ printk(KERN_CRIT "%s: unable to disable loopback\n",
+ dev->name);
+
+ port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &
+ ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */
+ mdio_write(dev, port->plat->phy, MII_BMCR,
+ port->mii_bmcr | BMCR_PDOWN);
+
+ if (!ports_open)
+ qmgr_disable_irq(TXDONE_QUEUE);
+ cancel_rearming_delayed_work(&port->mdio_thread);
+ destroy_queues(port);
+ release_queues(port);
+ return 0;
+}
+
+static int __devinit eth_init_one(struct platform_device *pdev)
+{
+ struct port *port;
+ struct net_device *dev;
+ struct eth_plat_info *plat = pdev->dev.platform_data;
+ u32 regs_phys;
+ int err;
+
+ if (!(dev = alloc_etherdev(sizeof(struct port))))
+ return -ENOMEM;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ port = netdev_priv(dev);
+ port->netdev = dev;
+ port->id = pdev->id;
+
+ switch (port->id) {
+ case IXP4XX_ETH_NPEA:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthA_BASE_VIRT;
+ regs_phys = IXP4XX_EthA_BASE_PHYS;
+ break;
+ case IXP4XX_ETH_NPEB:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+ regs_phys = IXP4XX_EthB_BASE_PHYS;
+ break;
+ case IXP4XX_ETH_NPEC:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
+ regs_phys = IXP4XX_EthC_BASE_PHYS;
+ break;
+ default:
+ err = -ENOSYS;
+ goto err_free;
+ }
+
+ dev->open = eth_open;
+ dev->hard_start_xmit = eth_xmit;
+ dev->stop = eth_close;
+ dev->get_stats = eth_stats;
+ dev->do_ioctl = eth_ioctl;
+ dev->set_multicast_list = eth_set_mcast_list;
+ dev->tx_queue_len = 100;
+
+ netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT);
+
+ if (!(port->npe = npe_request(NPE_ID(port->id)))) {
+ err = -EIO;
+ goto err_free;
+ }
+
+ if (register_netdev(dev)) {
+ err = -EIO;
+ goto err_npe_rel;
+ }
+
+ port->mem_res = request_mem_region(regs_phys, REGS_SIZE, dev->name);
+ if (!port->mem_res) {
+ err = -EBUSY;
+ goto err_unreg;
+ }
+
+ port->plat = plat;
+ npe_port_tab[NPE_ID(port->id)] = port;
+ memcpy(dev->dev_addr, plat->hwaddr, ETH_ALEN);
+
+ platform_set_drvdata(pdev, dev);
+
+ __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+ &port->regs->core_control);
+ udelay(50);
+ __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+ udelay(50);
+
+ port->mii.dev = dev;
+ port->mii.mdio_read = mdio_read;
+ port->mii.mdio_write = mdio_write;
+ port->mii.phy_id = plat->phy;
+ port->mii.phy_id_mask = 0x1F;
+ port->mii.reg_num_mask = 0x1F;
+
+ printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
+ npe_name(port->npe));
+
+ phy_reset(dev, plat->phy);
+ port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &
+ ~(BMCR_RESET | BMCR_PDOWN);
+ mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);
+
+ INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
+ return 0;
+
+err_unreg:
+ unregister_netdev(dev);
+err_npe_rel:
+ npe_release(port->npe);
+err_free:
+ free_netdev(dev);
+ return err;
+}
+
+static int __devexit eth_remove_one(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct port *port = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ npe_port_tab[NPE_ID(port->id)] = NULL;
+ platform_set_drvdata(pdev, NULL);
+ npe_release(port->npe);
+ release_resource(port->mem_res);
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver drv = {
+ .driver.name = DRV_NAME,
+ .probe = eth_init_one,
+ .remove = eth_remove_one,
+};
+
+static int __init eth_init_module(void)
+{
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+ return -ENOSYS;
+
+ /* All MII PHY accesses use NPE-B Ethernet registers */
+ spin_lock_init(&mdio_lock);
+ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+ __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+ return platform_driver_register(&drv);
+}
+
+static void __exit eth_cleanup_module(void)
+{
+ platform_driver_unregister(&drv);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_DESCRIPTION("Intel IXP4xx Ethernet driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ixp4xx_eth");
+module_init(eth_init_module);
+module_exit(eth_cleanup_module);
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 0afe522b8f7b..9c2394d49428 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -1,7 +1,7 @@
/*
* Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
* Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
*
* Derived from Intel e1000 driver
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
@@ -36,7 +36,6 @@
* A very incomplete list of things that need to be dealt with:
*
* TODO:
- * Wake on LAN.
* Add more ethtool functions.
* Fix abstruse irq enable/disable condition described here:
* http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
@@ -638,21 +637,18 @@ static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw)
}
/*
- *TODO: do something or get rid of this
+ * Force the PHY into power saving mode using vendor magic.
*/
#ifdef CONFIG_PM
-static s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
+static void atl1_phy_enter_power_saving(struct atl1_hw *hw)
{
-/* s32 ret_val;
- * u16 phy_data;
- */
+ atl1_write_phy_reg(hw, MII_DBG_ADDR, 0);
+ atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E);
+ atl1_write_phy_reg(hw, MII_DBG_ADDR, 2);
+ atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000);
+ atl1_write_phy_reg(hw, MII_DBG_ADDR, 3);
+ atl1_write_phy_reg(hw, MII_DBG_DATA, 0);
-/*
- ret_val = atl1_write_phy_reg(hw, ...);
- ret_val = atl1_write_phy_reg(hw, ...);
- ....
-*/
- return 0;
}
#endif
@@ -2784,64 +2780,93 @@ static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
struct atl1_hw *hw = &adapter->hw;
u32 ctrl = 0;
u32 wufc = adapter->wol;
+ u32 val;
+ int retval;
+ u16 speed;
+ u16 duplex;
netif_device_detach(netdev);
if (netif_running(netdev))
atl1_down(adapter);
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
- if (ctrl & BMSR_LSTATUS)
+ val = ctrl & BMSR_LSTATUS;
+ if (val)
wufc &= ~ATLX_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);
- atlx_set_multi(netdev);
+ if (val && wufc) {
+ val = atl1_get_speed_and_duplex(hw, &speed, &duplex);
+ if (val) {
+ if (netif_msg_ifdown(adapter))
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "error getting speed/duplex\n");
+ goto disable_wol;
+ }
ctrl = 0;
- /* turn on magic packet wol */
- if (wufc & ATLX_WUFC_MAG)
- ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
- /* turn on Link change WOL */
- if (wufc & ATLX_WUFC_LNKC)
- ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+ /* enable magic packet WOL */
+ if (wufc & ATLX_WUFC_MAG)
+ ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_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 & ATLX_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 & ATLX_WUFC_BC)
+ ioread32(hw->hw_addr + REG_WOL_CTRL);
+
+ /* configure the mac */
+ ctrl = MAC_CTRL_RX_EN;
+ ctrl |= ((u32)((speed == SPEED_1000) ? MAC_CTRL_SPEED_1000 :
+ MAC_CTRL_SPEED_10_100) << MAC_CTRL_SPEED_SHIFT);
+ if (duplex == FULL_DUPLEX)
+ ctrl |= MAC_CTRL_DUPLX;
+ ctrl |= (((u32)adapter->hw.preamble_len &
+ MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+ if (adapter->vlgrp)
+ ctrl |= MAC_CTRL_RMV_VLAN;
+ if (wufc & ATLX_WUFC_MAG)
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);
- } else {
- iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0);
+ ioread32(hw->hw_addr + REG_MAC_CTRL);
+
+ /* poke the PHY */
+ ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+ ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+ iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC);
+ ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+ goto exit;
}
- pci_save_state(pdev);
+ if (!val && wufc) {
+ ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+ iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+ ioread32(hw->hw_addr + REG_WOL_CTRL);
+ iowrite32(0, hw->hw_addr + REG_MAC_CTRL);
+ ioread32(hw->hw_addr + REG_MAC_CTRL);
+ hw->phy_configured = false;
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+ goto exit;
+ }
+
+disable_wol:
+ iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+ ioread32(hw->hw_addr + REG_WOL_CTRL);
+ ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+ ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+ iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC);
+ ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
+ atl1_phy_enter_power_saving(hw);
+ hw->phy_configured = false;
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+exit:
+ if (netif_running(netdev))
+ pci_disable_msi(adapter->pdev);
pci_disable_device(pdev);
-
- pci_set_power_state(pdev, PCI_D3hot);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
@@ -2855,20 +2880,26 @@ static int atl1_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- /* FIXME: check and handle */
err = pci_enable_device(pdev);
+ if (err) {
+ if (netif_msg_ifup(adapter))
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "error enabling pci device\n");
+ return err;
+ }
+
+ pci_set_master(pdev);
+ iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
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);
+ atl1_reset_hw(&adapter->hw);
+ adapter->cmb.cmb->int_stats = 0;
if (netif_running(netdev))
atl1_up(adapter);
netif_device_attach(netdev);
- atl1_via_workaround(adapter);
-
return 0;
}
#else
@@ -2876,6 +2907,13 @@ static int atl1_resume(struct pci_dev *pdev)
#define atl1_resume NULL
#endif
+static void atl1_shutdown(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PM
+ atl1_suspend(pdev, PMSG_SUSPEND);
+#endif
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void atl1_poll_controller(struct net_device *netdev)
{
@@ -3122,7 +3160,8 @@ static struct pci_driver atl1_driver = {
.probe = atl1_probe,
.remove = __devexit_p(atl1_remove),
.suspend = atl1_suspend,
- .resume = atl1_resume
+ .resume = atl1_resume,
+ .shutdown = atl1_shutdown
};
/*
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 51893d66eae1..a5015b14a429 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -1,7 +1,7 @@
/*
* Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
* Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
*
* Derived from Intel e1000 driver
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index f06b854e2501..b3e7fcf0f6e7 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -2,7 +2,7 @@
*
* Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
* Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
* Copyright(c) 2007 Atheros Corporation. All rights reserved.
*
* Derived from Intel e1000 driver
diff --git a/drivers/net/atlx/atlx.h b/drivers/net/atlx/atlx.h
index 3be7c09734d4..297a03da6b7f 100644
--- a/drivers/net/atlx/atlx.h
+++ b/drivers/net/atlx/atlx.h
@@ -2,7 +2,7 @@
*
* Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
* Copyright(c) 2006 - 2007 Chris Snook <csnook@redhat.com>
- * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ * Copyright(c) 2006 - 2008 Jay Cliburn <jcliburn@gmail.com>
* Copyright(c) 2007 Atheros Corporation. All rights reserved.
*
* Derived from Intel e1000 driver
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include <linux/types.h>
-#define ATLX_DRIVER_VERSION "2.1.1"
+#define ATLX_DRIVER_VERSION "2.1.3"
MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \
Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
MODULE_LICENSE("GPL");
@@ -460,6 +460,9 @@ MODULE_VERSION(ATLX_DRIVER_VERSION);
#define MII_ATLX_PSSR_100MBS 0x4000 /* 01=100Mbs */
#define MII_ATLX_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+#define MII_DBG_ADDR 0x1D
+#define MII_DBG_DATA 0x1E
+
/* PCI Command Register Bit Definitions */
#define PCI_REG_COMMAND 0x04 /* PCI Command Register */
#define CMD_IO_SPACE 0x0001
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 4fec8581bfd7..89c0018132ec 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -27,6 +27,7 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
@@ -42,7 +43,7 @@
#define DRV_NAME "bfin_mac"
#define DRV_VERSION "1.1"
#define DRV_AUTHOR "Bryan Wu, Luke Yang"
-#define DRV_DESC "Blackfin BF53[67] BF527 on-chip Ethernet MAC driver"
+#define DRV_DESC "Blackfin on-chip Ethernet MAC driver"
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -73,8 +74,14 @@ static struct net_dma_desc_tx *current_tx_ptr;
static struct net_dma_desc_tx *tx_desc;
static struct net_dma_desc_rx *rx_desc;
-static void bf537mac_disable(void);
-static void bf537mac_enable(void);
+#if defined(CONFIG_BFIN_MAC_RMII)
+static u16 pin_req[] = P_RMII0;
+#else
+static u16 pin_req[] = P_MII0;
+#endif
+
+static void bfin_mac_disable(void);
+static void bfin_mac_enable(void);
static void desc_list_free(void)
{
@@ -243,27 +250,6 @@ init_error:
/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
-/* Set FER regs to MUX in Ethernet pins */
-static int setup_pin_mux(int action)
-{
-#if defined(CONFIG_BFIN_MAC_RMII)
- u16 pin_req[] = P_RMII0;
-#else
- u16 pin_req[] = P_MII0;
-#endif
-
- if (action) {
- if (peripheral_request_list(pin_req, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
- return -EFAULT;
- }
- } else
- peripheral_free_list(pin_req);
-
- return 0;
-}
-
/*
* MII operations
*/
@@ -322,9 +308,9 @@ static int mdiobus_reset(struct mii_bus *bus)
return 0;
}
-static void bf537_adjust_link(struct net_device *dev)
+static void bfin_mac_adjust_link(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = lp->phydev;
unsigned long flags;
int new_state = 0;
@@ -395,7 +381,7 @@ static void bf537_adjust_link(struct net_device *dev)
static int mii_probe(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = NULL;
unsigned short sysctl;
int i;
@@ -431,10 +417,10 @@ static int mii_probe(struct net_device *dev)
}
#if defined(CONFIG_BFIN_MAC_RMII)
- phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_RMII);
#else
- phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
#endif
@@ -469,6 +455,51 @@ static int mii_probe(struct net_device *dev)
return 0;
}
+/*
+ * Ethtool support
+ */
+
+static int
+bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
+ if (lp->phydev)
+ return phy_ethtool_gset(lp->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static int
+bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (lp->phydev)
+ return phy_ethtool_sset(lp->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+ strcpy(info->bus_info, dev->dev.bus_id);
+}
+
+static struct ethtool_ops bfin_mac_ethtool_ops = {
+ .get_settings = bfin_mac_ethtool_getsettings,
+ .set_settings = bfin_mac_ethtool_setsettings,
+ .get_link = ethtool_op_get_link,
+ .get_drvinfo = bfin_mac_ethtool_getdrvinfo,
+};
+
/**************************************************************************/
void setup_system_regs(struct net_device *dev)
{
@@ -511,7 +542,7 @@ static void setup_mac_addr(u8 *mac_addr)
bfin_write_EMAC_ADDRHI(addr_hi);
}
-static int bf537mac_set_mac_address(struct net_device *dev, void *p)
+static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
@@ -573,7 +604,7 @@ adjust_head:
}
-static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
unsigned int data;
@@ -631,7 +662,7 @@ out:
return 0;
}
-static void bf537mac_rx(struct net_device *dev)
+static void bfin_mac_rx(struct net_device *dev)
{
struct sk_buff *skb, *new_skb;
unsigned short len;
@@ -680,7 +711,7 @@ out:
}
/* interrupt routine to handle rx and error signal */
-static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+static irqreturn_t bfin_mac_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
int number = 0;
@@ -700,21 +731,21 @@ get_one_packet:
}
real_rx:
- bf537mac_rx(dev);
+ bfin_mac_rx(dev);
number++;
goto get_one_packet;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-static void bf537mac_poll(struct net_device *dev)
+static void bfin_mac_poll(struct net_device *dev)
{
disable_irq(IRQ_MAC_RX);
- bf537mac_interrupt(IRQ_MAC_RX, dev);
+ bfin_mac_interrupt(IRQ_MAC_RX, dev);
enable_irq(IRQ_MAC_RX);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
-static void bf537mac_disable(void)
+static void bfin_mac_disable(void)
{
unsigned int opmode;
@@ -728,7 +759,7 @@ static void bf537mac_disable(void)
/*
* Enable Interrupts, Receive, and Transmit
*/
-static void bf537mac_enable(void)
+static void bfin_mac_enable(void)
{
u32 opmode;
@@ -766,23 +797,23 @@ static void bf537mac_enable(void)
}
/* Our watchdog timed out. Called by the networking layer */
-static void bf537mac_timeout(struct net_device *dev)
+static void bfin_mac_timeout(struct net_device *dev)
{
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
- bf537mac_disable();
+ bfin_mac_disable();
/* reset tx queue */
tx_list_tail = tx_list_head->next;
- bf537mac_enable();
+ bfin_mac_enable();
/* We can accept TX packets again */
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
-static void bf537mac_multicast_hash(struct net_device *dev)
+static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
struct dev_mc_list *dmi = dev->mc_list;
@@ -821,7 +852,7 @@ static void bf537mac_multicast_hash(struct net_device *dev)
* promiscuous mode (for TCPDUMP and cousins) or accept
* a select set of multicast packets
*/
-static void bf537mac_set_multicast_list(struct net_device *dev)
+static void bfin_mac_set_multicast_list(struct net_device *dev)
{
u32 sysctl;
@@ -840,7 +871,7 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= HM;
bfin_write_EMAC_OPMODE(sysctl);
- bf537mac_multicast_hash(dev);
+ bfin_mac_multicast_hash(dev);
} else {
/* clear promisc or multicast mode */
sysctl = bfin_read_EMAC_OPMODE();
@@ -852,7 +883,7 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
/*
* this puts the device in an inactive state
*/
-static void bf537mac_shutdown(struct net_device *dev)
+static void bfin_mac_shutdown(struct net_device *dev)
{
/* Turn off the EMAC */
bfin_write_EMAC_OPMODE(0x00000000);
@@ -866,9 +897,9 @@ static void bf537mac_shutdown(struct net_device *dev)
*
* Set up everything, reset the card, etc..
*/
-static int bf537mac_open(struct net_device *dev)
+static int bfin_mac_open(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
int retval;
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
@@ -891,8 +922,8 @@ static int bf537mac_open(struct net_device *dev)
phy_start(lp->phydev);
phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
setup_system_regs(dev);
- bf537mac_disable();
- bf537mac_enable();
+ bfin_mac_disable();
+ bfin_mac_enable();
pr_debug("hardware init finished\n");
netif_start_queue(dev);
netif_carrier_on(dev);
@@ -906,9 +937,9 @@ static int bf537mac_open(struct net_device *dev)
* and not talk to the outside world. Caused by
* an 'ifconfig ethX down'
*/
-static int bf537mac_close(struct net_device *dev)
+static int bfin_mac_close(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
@@ -918,7 +949,7 @@ static int bf537mac_close(struct net_device *dev)
phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
/* clear everything */
- bf537mac_shutdown(dev);
+ bfin_mac_shutdown(dev);
/* free the rx/tx buffers */
desc_list_free();
@@ -926,46 +957,59 @@ static int bf537mac_close(struct net_device *dev)
return 0;
}
-static int __init bf537mac_probe(struct net_device *dev)
+static int __init bfin_mac_probe(struct platform_device *pdev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
- int retval;
- int i;
+ struct net_device *ndev;
+ struct bfin_mac_local *lp;
+ int rc, i;
+
+ ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
+ if (!ndev) {
+ dev_err(&pdev->dev, "Cannot allocate net device!\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ platform_set_drvdata(pdev, ndev);
+ lp = netdev_priv(ndev);
/* Grab the MAC address in the MAC */
- *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
- *(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
+ *(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
+ *(__le16 *) (&(ndev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
/* probe mac */
/*todo: how to proble? which is revision_register */
bfin_write_EMAC_ADDRLO(0x12345678);
if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
- pr_debug("can't detect bf537 mac!\n");
- retval = -ENODEV;
- goto err_out;
+ dev_err(&pdev->dev, "Cannot detect Blackfin on-chip ethernet MAC controller!\n");
+ rc = -ENODEV;
+ goto out_err_probe_mac;
}
/* set the GPIO pins to Ethernet mode */
- retval = setup_pin_mux(1);
- if (retval)
- return retval;
-
- /*Is it valid? (Did bootloader initialize it?) */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- /* Grab the MAC from the board somehow - this is done in the
- arch/blackfin/mach-bf537/boards/eth_mac.c */
- bfin_get_ether_addr(dev->dev_addr);
+ rc = peripheral_request_list(pin_req, DRV_NAME);
+ if (rc) {
+ dev_err(&pdev->dev, "Requesting peripherals failed!\n");
+ rc = -EFAULT;
+ goto out_err_setup_pin_mux;
}
+ /*
+ * Is it valid? (Did bootloader initialize it?)
+ * Grab the MAC from the board somehow
+ * this is done in the arch/blackfin/mach-bfxxx/boards/eth_mac.c
+ */
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ bfin_get_ether_addr(ndev->dev_addr);
+
/* If still not valid, get a random one */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- random_ether_addr(dev->dev_addr);
- }
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ random_ether_addr(ndev->dev_addr);
- setup_mac_addr(dev->dev_addr);
+ setup_mac_addr(ndev->dev_addr);
/* MDIO bus initial */
- lp->mii_bus.priv = dev;
+ lp->mii_bus.priv = ndev;
lp->mii_bus.read = mdiobus_read;
lp->mii_bus.write = mdiobus_write;
lp->mii_bus.reset = mdiobus_reset;
@@ -975,86 +1019,86 @@ static int __init bf537mac_probe(struct net_device *dev)
for (i = 0; i < PHY_MAX_ADDR; ++i)
lp->mii_bus.irq[i] = PHY_POLL;
- mdiobus_register(&lp->mii_bus);
+ rc = mdiobus_register(&lp->mii_bus);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
+ goto out_err_mdiobus_register;
+ }
- retval = mii_probe(dev);
- if (retval)
- return retval;
+ rc = mii_probe(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "MII Probe failed!\n");
+ goto out_err_mii_probe;
+ }
/* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
-
- dev->open = bf537mac_open;
- dev->stop = bf537mac_close;
- dev->hard_start_xmit = bf537mac_hard_start_xmit;
- dev->set_mac_address = bf537mac_set_mac_address;
- dev->tx_timeout = bf537mac_timeout;
- dev->set_multicast_list = bf537mac_set_multicast_list;
+ ether_setup(ndev);
+
+ ndev->open = bfin_mac_open;
+ ndev->stop = bfin_mac_close;
+ ndev->hard_start_xmit = bfin_mac_hard_start_xmit;
+ ndev->set_mac_address = bfin_mac_set_mac_address;
+ ndev->tx_timeout = bfin_mac_timeout;
+ ndev->set_multicast_list = bfin_mac_set_multicast_list;
#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = bf537mac_poll;
+ ndev->poll_controller = bfin_mac_poll;
#endif
+ ndev->ethtool_ops = &bfin_mac_ethtool_ops;
spin_lock_init(&lp->lock);
/* now, enable interrupts */
/* register irq handler */
- if (request_irq
- (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
- "EMAC_RX", dev)) {
- printk(KERN_WARNING DRV_NAME
- ": Unable to attach BlackFin MAC RX interrupt\n");
- return -EBUSY;
+ rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
+ rc = -EBUSY;
+ goto out_err_request_irq;
}
-
- retval = register_netdev(dev);
- if (retval == 0) {
- /* now, print out the card info, in a short format.. */
- printk(KERN_INFO "%s: Version %s, %s\n",
- DRV_NAME, DRV_VERSION, DRV_DESC);
- }
-
-err_out:
- return retval;
-}
-
-static int bfin_mac_probe(struct platform_device *pdev)
-{
- struct net_device *ndev;
-
- ndev = alloc_etherdev(sizeof(struct bf537mac_local));
- if (!ndev) {
- printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
- return -ENOMEM;
+ rc = register_netdev(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register net device!\n");
+ goto out_err_reg_ndev;
}
- SET_NETDEV_DEV(ndev, &pdev->dev);
+ /* now, print out the card info, in a short format.. */
+ dev_info(&pdev->dev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
- platform_set_drvdata(pdev, ndev);
+ return 0;
- if (bf537mac_probe(ndev) != 0) {
- platform_set_drvdata(pdev, NULL);
- free_netdev(ndev);
- printk(KERN_WARNING DRV_NAME ": not found\n");
- return -ENODEV;
- }
+out_err_reg_ndev:
+ free_irq(IRQ_MAC_RX, ndev);
+out_err_request_irq:
+out_err_mii_probe:
+ mdiobus_unregister(&lp->mii_bus);
+out_err_mdiobus_register:
+ peripheral_free_list(pin_req);
+out_err_setup_pin_mux:
+out_err_probe_mac:
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
- return 0;
+ return rc;
}
static int bfin_mac_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct bfin_mac_local *lp = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL);
+ mdiobus_unregister(&lp->mii_bus);
+
unregister_netdev(ndev);
free_irq(IRQ_MAC_RX, ndev);
free_netdev(ndev);
- setup_pin_mux(0);
+ peripheral_free_list(pin_req);
return 0;
}
@@ -1065,7 +1109,7 @@ static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
- bf537mac_close(net_dev);
+ bfin_mac_close(net_dev);
return 0;
}
@@ -1075,7 +1119,7 @@ static int bfin_mac_resume(struct platform_device *pdev)
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
- bf537mac_open(net_dev);
+ bfin_mac_open(net_dev);
return 0;
}
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index f774d5a36942..beff51064ff4 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -49,7 +49,7 @@ struct net_dma_desc_tx {
struct status_area_tx status;
};
-struct bf537mac_local {
+struct bfin_mac_local {
/*
* these are things that the kernel wants me to keep, so users
* can find out semi-useless statistics of how well the card is
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 15853be4680a..4b46e68183e0 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -56,8 +56,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.7.4"
-#define DRV_MODULE_RELDATE "February 18, 2008"
+#define DRV_MODULE_VERSION "1.7.5"
+#define DRV_MODULE_RELDATE "April 29, 2008"
#define RUN_AT(x) (jiffies + (x))
@@ -1631,8 +1631,10 @@ bnx2_set_default_remote_link(struct bnx2 *bp)
static void
bnx2_set_default_link(struct bnx2 *bp)
{
- if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
- return bnx2_set_default_remote_link(bp);
+ if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
+ bnx2_set_default_remote_link(bp);
+ return;
+ }
bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
bp->req_line_speed = 0;
@@ -1715,7 +1717,6 @@ bnx2_remote_phy_event(struct bnx2 *bp)
break;
}
- spin_lock(&bp->phy_lock);
bp->flow_ctrl = 0;
if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
(AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
@@ -1737,7 +1738,6 @@ bnx2_remote_phy_event(struct bnx2 *bp)
if (old_port != bp->phy_port)
bnx2_set_default_link(bp);
- spin_unlock(&bp->phy_lock);
}
if (bp->link_up != link_up)
bnx2_report_link(bp);
@@ -2222,6 +2222,11 @@ bnx2_init_5709_context(struct bnx2 *bp)
for (i = 0; i < bp->ctx_pages; i++) {
int j;
+ if (bp->ctx_blk[i])
+ memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
+ else
+ return -ENOMEM;
+
REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
(bp->ctx_blk_mapping[i] & 0xffffffff) |
BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
@@ -2445,14 +2450,15 @@ bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
static void
bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
{
- if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE)) {
- spin_lock(&bp->phy_lock);
+ spin_lock(&bp->phy_lock);
+
+ if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
bnx2_set_link(bp);
- spin_unlock(&bp->phy_lock);
- }
if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
bnx2_set_remote_link(bp);
+ spin_unlock(&bp->phy_lock);
+
}
static inline u16
@@ -3174,6 +3180,12 @@ load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
int i;
u32 val;
+ if (rv2p_proc == RV2P_PROC2 && CHIP_NUM(bp) == CHIP_NUM_5709) {
+ val = le32_to_cpu(rv2p_code[XI_RV2P_PROC2_MAX_BD_PAGE_LOC]);
+ val &= ~XI_RV2P_PROC2_BD_PAGE_SIZE_MSK;
+ val |= XI_RV2P_PROC2_BD_PAGE_SIZE;
+ rv2p_code[XI_RV2P_PROC2_MAX_BD_PAGE_LOC] = cpu_to_le32(val);
+ }
for (i = 0; i < rv2p_code_len; i += 8) {
REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code));
@@ -4215,13 +4227,6 @@ bnx2_init_remote_phy(struct bnx2 *bp)
if (netif_running(bp->dev)) {
u32 sig;
- if (val & BNX2_LINK_STATUS_LINK_UP) {
- bp->link_up = 1;
- netif_carrier_on(bp->dev);
- } else {
- bp->link_up = 0;
- netif_carrier_off(bp->dev);
- }
sig = BNX2_DRV_ACK_CAP_SIGNATURE |
BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
@@ -4878,6 +4883,8 @@ bnx2_init_nic(struct bnx2 *bp)
spin_lock_bh(&bp->phy_lock);
bnx2_init_phy(bp);
bnx2_set_link(bp);
+ if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
+ bnx2_remote_phy_event(bp);
spin_unlock_bh(&bp->phy_lock);
return 0;
}
@@ -4920,7 +4927,7 @@ bnx2_test_registers(struct bnx2 *bp)
{ 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
{ 0x1000, 0, 0x00000000, 0x00000001 },
- { 0x1004, 0, 0x00000000, 0x000f0001 },
+ { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
{ 0x1408, 0, 0x01c00800, 0x00000000 },
{ 0x149c, 0, 0x8000ffff, 0x00000000 },
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index e6ffa2769f3d..ed0514cba0ee 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -3173,251 +3173,267 @@ static struct fw_info bnx2_rxp_fw_09 = {
};
static u8 bnx2_xi_rv2p_proc1[] = {
- /* Date: 01/14/2008 15:44 */
- 0xc5, 0x56, 0xcd, 0x6b, 0x13, 0x51, 0x10, 0x9f, 0xdd, 0x7c, 0x6c, 0x9a,
- 0x6c, 0xb2, 0xa1, 0x6a, 0x09, 0x35, 0xd2, 0x58, 0x7a, 0x30, 0x6d, 0xc4,
- 0x56, 0x3d, 0x78, 0x28, 0x54, 0x7a, 0x11, 0xac, 0xa7, 0x1e, 0x44, 0xc4,
- 0xcf, 0x20, 0x05, 0xf5, 0x8f, 0x70, 0x51, 0xab, 0x20, 0x78, 0x28, 0x68,
- 0xb4, 0x7e, 0xa0, 0x27, 0x15, 0xf1, 0x90, 0x1c, 0x04, 0x05, 0x45, 0x50,
- 0xf0, 0xa4, 0x37, 0x41, 0xbd, 0x54, 0xc5, 0x0f, 0xf0, 0xe2, 0x45, 0x8f,
- 0xda, 0xf8, 0xde, 0xcc, 0xef, 0xd9, 0xdd, 0x4d, 0xd2, 0x14, 0x0f, 0x1a,
- 0x68, 0x7f, 0xec, 0xdb, 0xdf, 0x9b, 0x37, 0xf3, 0x9b, 0x79, 0x33, 0x9b,
- 0x27, 0x22, 0x9b, 0xfc, 0xc6, 0x80, 0x42, 0x72, 0xad, 0x58, 0x4a, 0x81,
- 0x45, 0x74, 0xcf, 0x65, 0xf4, 0x37, 0x91, 0xfc, 0x46, 0x04, 0xfc, 0x91,
- 0xbc, 0xfa, 0xff, 0x9d, 0x26, 0x4a, 0x1a, 0x63, 0x34, 0xb1, 0x5e, 0xe3,
- 0x24, 0x3d, 0x29, 0x15, 0x14, 0xfe, 0x6a, 0x92, 0xaf, 0x9f, 0x87, 0xea,
- 0x0f, 0x1a, 0x19, 0xb6, 0xfb, 0x0e, 0xfb, 0xdf, 0xc4, 0x04, 0xb7, 0x55,
- 0x52, 0x62, 0x07, 0x48, 0x1b, 0xf3, 0x0c, 0xaf, 0xe6, 0xf4, 0x73, 0xd1,
- 0xf2, 0x37, 0xe2, 0x7c, 0x5b, 0xd6, 0x17, 0xe6, 0x3c, 0xbd, 0x4e, 0xef,
- 0x27, 0xf5, 0xb3, 0x97, 0x3e, 0xdd, 0x48, 0xb1, 0x5d, 0x79, 0xdf, 0x9b,
- 0x3e, 0xcd, 0xfb, 0x5c, 0x4b, 0xec, 0xa9, 0x3f, 0xde, 0xbf, 0x55, 0xd9,
- 0x81, 0xdf, 0x24, 0x76, 0x0e, 0x96, 0xf4, 0xfa, 0x76, 0xf0, 0xc6, 0xc1,
- 0x2b, 0xb6, 0xf0, 0x16, 0xe6, 0x34, 0x3a, 0x54, 0xad, 0xe8, 0x78, 0x06,
- 0x49, 0xe2, 0x49, 0xd0, 0x4c, 0xca, 0x15, 0x9d, 0x06, 0x84, 0xfd, 0x6e,
- 0x58, 0xef, 0x57, 0xbe, 0x0d, 0x6b, 0xde, 0x82, 0x8a, 0xdb, 0xc4, 0x1b,
- 0xe6, 0x39, 0x15, 0x63, 0x57, 0xf3, 0xde, 0x2a, 0x9e, 0x89, 0x2f, 0x18,
- 0x57, 0x26, 0x10, 0x57, 0x24, 0xde, 0x96, 0xf8, 0x82, 0x7a, 0xa5, 0xda,
- 0xf8, 0xaf, 0xcf, 0x51, 0xbe, 0xf0, 0x39, 0x49, 0xe8, 0x9c, 0x8c, 0xec,
- 0x4b, 0x76, 0x88, 0xfb, 0x93, 0x35, 0xb3, 0x21, 0xec, 0x3f, 0x91, 0xb6,
- 0xf7, 0x54, 0xf9, 0x8d, 0xf5, 0x72, 0x3b, 0x1d, 0x12, 0xd0, 0xe1, 0x31,
- 0xe2, 0x9b, 0xa2, 0x21, 0xbb, 0xc0, 0xef, 0xe3, 0xbc, 0x7f, 0xad, 0xf2,
- 0x47, 0xe3, 0x3a, 0xe0, 0x7a, 0xe0, 0x01, 0xe0, 0x7e, 0xe0, 0x1a, 0xe0,
- 0x6a, 0xe0, 0x2a, 0x60, 0x2f, 0xf0, 0x32, 0x30, 0x0f, 0xf4, 0x80, 0x39,
- 0xe0, 0x05, 0xa0, 0x0b, 0xcc, 0x00, 0x6b, 0xc0, 0xab, 0xc0, 0x14, 0xf0,
- 0x28, 0xf0, 0x21, 0xf0, 0x31, 0xf0, 0x0b, 0xf0, 0x1c, 0xd0, 0xb1, 0x60,
- 0x0f, 0xa8, 0x7e, 0x3e, 0xee, 0x47, 0x48, 0xa7, 0xeb, 0xa8, 0x7f, 0xad,
- 0x33, 0xde, 0x97, 0x0d, 0x0f, 0xf9, 0x65, 0x9d, 0x2e, 0x83, 0xd7, 0x5b,
- 0xbf, 0x19, 0xb9, 0x27, 0xa5, 0xae, 0xf7, 0x23, 0x9a, 0x37, 0x8f, 0xe3,
- 0x39, 0xb4, 0xc3, 0xe3, 0x73, 0x72, 0x49, 0x59, 0x37, 0x6e, 0xed, 0xf1,
- 0x04, 0x8f, 0xa4, 0x05, 0x3f, 0xa7, 0x7b, 0xd4, 0xff, 0x66, 0x73, 0x26,
- 0x23, 0xcf, 0x87, 0xb3, 0x46, 0x67, 0x63, 0xc7, 0xf8, 0xd3, 0xcd, 0x8f,
- 0x4e, 0xe7, 0x19, 0xbf, 0xba, 0x9d, 0x2b, 0x58, 0xb5, 0xc3, 0xf1, 0x5f,
- 0x19, 0x15, 0x8c, 0x8f, 0x31, 0x54, 0xdc, 0x64, 0x5c, 0xe3, 0x56, 0xf7,
- 0xb9, 0x39, 0x47, 0xa3, 0x5b, 0xa8, 0xf1, 0x7d, 0x89, 0x53, 0x2d, 0xa9,
- 0xed, 0xfe, 0x6c, 0x9e, 0x17, 0x5e, 0xff, 0xe1, 0x97, 0x8c, 0x85, 0x2b,
- 0x2f, 0x84, 0xff, 0xba, 0xe4, 0x32, 0xee, 0x1e, 0xa1, 0xc8, 0xcf, 0xbc,
- 0x97, 0xfb, 0xe8, 0xb3, 0xdf, 0x3f, 0x2c, 0xbf, 0x61, 0xce, 0xc1, 0xbe,
- 0xe3, 0x26, 0x8f, 0x79, 0xf6, 0x73, 0x90, 0xe4, 0x79, 0xba, 0x2c, 0xef,
- 0xa7, 0xcb, 0xb8, 0xcf, 0x83, 0xe1, 0x7a, 0x90, 0x7b, 0x11, 0x43, 0xbe,
- 0xf7, 0xe2, 0x5e, 0x44, 0xef, 0x71, 0xaa, 0x7e, 0x73, 0x2e, 0x58, 0x2f,
- 0x05, 0xaa, 0x8e, 0xc1, 0x9f, 0x96, 0x3c, 0x9b, 0xbe, 0x6c, 0xea, 0x9d,
- 0x97, 0xeb, 0x7e, 0x2c, 0xa4, 0xdf, 0x76, 0xaa, 0x04, 0xf3, 0x64, 0xb5,
- 0xa9, 0x97, 0x6e, 0xe7, 0x84, 0xec, 0xe5, 0x54, 0x06, 0xa8, 0xb5, 0x8e,
- 0x1d, 0xc4, 0x35, 0x81, 0x3a, 0x5e, 0xdb, 0x52, 0xc7, 0xa6, 0xdf, 0x4b,
- 0x3d, 0x77, 0xea, 0x5f, 0x7f, 0xdf, 0xa7, 0x85, 0xe7, 0x07, 0xea, 0xd3,
- 0xf4, 0x43, 0xe8, 0xe4, 0x30, 0xaf, 0xb8, 0x70, 0x5f, 0xf2, 0x26, 0xfd,
- 0x5c, 0x15, 0xa3, 0x1f, 0xf6, 0xd3, 0x31, 0xf1, 0x0d, 0x04, 0xfb, 0xe7,
- 0x50, 0x87, 0x7c, 0x05, 0xfb, 0x6e, 0x54, 0x97, 0x70, 0xdd, 0x4b, 0xfe,
- 0xd3, 0xd0, 0xa9, 0xbf, 0x4b, 0x5f, 0xe8, 0x01, 0x6f, 0xcd, 0x32, 0x3c,
- 0xb1, 0x3b, 0x59, 0x0e, 0xf6, 0x11, 0xaf, 0x89, 0xfe, 0x87, 0x7d, 0x7d,
- 0xf5, 0x47, 0x1d, 0xf2, 0x30, 0xfe, 0x7f, 0xf3, 0x80, 0xf9, 0x52, 0xb4,
- 0x24, 0x0f, 0x09, 0x5a, 0x99, 0xbe, 0x84, 0xf8, 0xa9, 0x83, 0xbe, 0x49,
- 0xe8, 0xf0, 0x6d, 0x71, 0x79, 0x7d, 0x33, 0xe0, 0x7d, 0x0d, 0xf0, 0xb8,
- 0x2e, 0xc6, 0xe5, 0xfe, 0x39, 0xd5, 0x2f, 0x11, 0xdd, 0xc6, 0x2a, 0xba,
- 0xaf, 0x9c, 0xa0, 0x06, 0xe2, 0x7a, 0x1b, 0x8a, 0x2f, 0xab, 0xfc, 0x93,
- 0xef, 0x84, 0x3b, 0x0d, 0xa3, 0x83, 0xbc, 0x2e, 0x55, 0x04, 0x6f, 0x33,
- 0x3f, 0x1f, 0xd0, 0x23, 0xac, 0x9b, 0xe8, 0x91, 0xa7, 0x5b, 0x7f, 0xfa,
- 0x8d, 0xc7, 0xf6, 0x46, 0xd1, 0xaf, 0x0f, 0xa1, 0x6f, 0x7e, 0x48, 0x4b,
- 0x5f, 0xae, 0x4e, 0x71, 0xff, 0xa4, 0x3e, 0xf4, 0xcf, 0x6a, 0x56, 0x9e,
- 0xfb, 0xb3, 0xf2, 0x1d, 0x36, 0xea, 0xb8, 0xcc, 0xeb, 0xcf, 0x0a, 0xf6,
- 0x65, 0xf4, 0xbe, 0x02, 0x7d, 0xdc, 0xc5, 0xf4, 0xca, 0xbc, 0x2b, 0x7d,
- 0x74, 0xfe, 0x05, 0xfa, 0xba, 0x67, 0x74, 0x42, 0xbc, 0x5b, 0xf4, 0x7a,
- 0x1f, 0x7f, 0xf2, 0x2c, 0xe9, 0xab, 0x38, 0xc3, 0xe2, 0xdf, 0x0d, 0x78,
- 0x5f, 0x32, 0xfb, 0x06, 0xb4, 0x9e, 0x4f, 0x16, 0xcd, 0xdc, 0x18, 0xdc,
- 0xa1, 0xfd, 0xf1, 0x28, 0xe7, 0x48, 0x3e, 0x05, 0x15, 0xcf, 0x76, 0xf4,
- 0xb6, 0xe2, 0xac, 0x2d, 0xcf, 0xb3, 0x27, 0xd9, 0xcc, 0xae, 0x59, 0xb3,
- 0x3e, 0xc9, 0x05, 0x3a, 0x7d, 0xf7, 0x19, 0xaf, 0xe7, 0x1a, 0x31, 0x59,
- 0x77, 0xa6, 0x8c, 0x1e, 0x1e, 0xc7, 0x57, 0x13, 0x3d, 0xf6, 0x5d, 0x14,
- 0xdc, 0x4b, 0x3b, 0x19, 0xd3, 0x35, 0x57, 0xe6, 0xca, 0xbc, 0x9b, 0x62,
- 0x24, 0xd6, 0xc3, 0xde, 0x2c, 0xf3, 0x21, 0x81, 0xbe, 0xde, 0x13, 0xc8,
- 0x53, 0x74, 0xde, 0xae, 0x34, 0x5f, 0xc1, 0x39, 0x60, 0xe6, 0x43, 0xb4,
- 0xdf, 0x67, 0x51, 0x67, 0xd7, 0xba, 0xd4, 0xa3, 0xe9, 0x9f, 0x97, 0x16,
- 0xe5, 0x1e, 0xb4, 0x9b, 0xb3, 0x1a, 0x73, 0x1d, 0xbe, 0x0f, 0x8a, 0xa8,
- 0x3f, 0x33, 0x0f, 0xdb, 0x7d, 0x07, 0x08, 0x7f, 0x65, 0xf3, 0x3f, 0xdf,
- 0x61, 0xfe, 0xff, 0xb3, 0x39, 0x5f, 0x58, 0xca, 0xa3, 0xa9, 0xd3, 0x60,
- 0x1e, 0x83, 0xf5, 0x1a, 0x9d, 0xc3, 0xcb, 0xcd, 0xdf, 0x1c, 0x74, 0x3e,
- 0x06, 0x9d, 0xe3, 0x94, 0x88, 0xb1, 0x30, 0x6e, 0xfc, 0x14, 0xdb, 0xb5,
- 0x67, 0x6d, 0xa6, 0xbb, 0x89, 0x33, 0x96, 0xc6, 0x9c, 0x7b, 0x46, 0x78,
- 0x71, 0x59, 0x2f, 0x18, 0x3c, 0x7b, 0x4a, 0xbe, 0xfb, 0x6c, 0xfa, 0x0d,
- 0x6d, 0x29, 0x98, 0xe1, 0x30, 0x0d, 0x00, 0x00, 0x00 };
+ /* Date: 04/25/2008 22:02 */
+ 0xbd, 0x56, 0x4f, 0x68, 0x1c, 0x55, 0x18, 0xff, 0x76, 0x76, 0x77, 0x66,
+ 0x33, 0x3b, 0xbb, 0xb3, 0xd8, 0x34, 0x4c, 0xb7, 0x2b, 0x59, 0x83, 0x97,
+ 0xdd, 0x6c, 0x69, 0xa2, 0x15, 0x04, 0x53, 0x5a, 0x72, 0x09, 0xd8, 0x9e,
+ 0x02, 0xb5, 0x52, 0x84, 0xb6, 0x8b, 0xf4, 0x52, 0x5a, 0x28, 0x78, 0x11,
+ 0x84, 0x0e, 0x6d, 0x93, 0x82, 0xe8, 0x61, 0xc1, 0x06, 0x12, 0x44, 0xa3,
+ 0x07, 0x95, 0x60, 0x61, 0x07, 0x3c, 0x78, 0x10, 0x14, 0x15, 0x11, 0x6c,
+ 0x0f, 0x85, 0x88, 0xf6, 0xd2, 0x54, 0x4b, 0x0b, 0x1e, 0x5b, 0x3c, 0xd6,
+ 0x8c, 0xef, 0xfb, 0xf3, 0x92, 0x99, 0x97, 0x9d, 0x24, 0xa7, 0x2e, 0xb4,
+ 0x3f, 0xbe, 0x37, 0xdf, 0xbf, 0xf7, 0xfd, 0xf9, 0xbd, 0xd4, 0x00, 0xc0,
+ 0x82, 0x30, 0x1a, 0x55, 0x08, 0x65, 0x2b, 0x5f, 0x52, 0x90, 0x03, 0xf8,
+ 0x1a, 0xf8, 0x57, 0xf4, 0x48, 0x0e, 0x0f, 0x8a, 0x3c, 0xce, 0x10, 0x8e,
+ 0xd7, 0xd4, 0xff, 0x17, 0xe0, 0x48, 0x13, 0x31, 0x0f, 0x47, 0x5e, 0x40,
+ 0x3c, 0x0c, 0xdf, 0x37, 0x03, 0x85, 0xff, 0xc5, 0x10, 0xa2, 0x3c, 0xdc,
+ 0xff, 0x36, 0x2a, 0x93, 0xff, 0x35, 0xb1, 0xff, 0x33, 0xcf, 0xf8, 0x6a,
+ 0xa7, 0xc4, 0x7e, 0x04, 0xe1, 0x40, 0x8d, 0x60, 0xb5, 0x87, 0xf2, 0x89,
+ 0x13, 0x60, 0xa3, 0x9f, 0x4f, 0x94, 0x02, 0xca, 0x8d, 0x5c, 0x78, 0x40,
+ 0xf2, 0xb2, 0x58, 0xef, 0x5e, 0xcf, 0xc7, 0x73, 0xb8, 0x3f, 0x8d, 0xf2,
+ 0x3e, 0xf7, 0x5a, 0x0f, 0x31, 0x80, 0x73, 0x25, 0x8f, 0xef, 0x33, 0xca,
+ 0x6e, 0xd7, 0xda, 0x68, 0xa7, 0x74, 0xdb, 0xe2, 0xb7, 0x88, 0x7e, 0xff,
+ 0x89, 0xd9, 0x2f, 0xfa, 0x4b, 0xfa, 0x69, 0x28, 0x3f, 0x78, 0x6e, 0x4b,
+ 0x5e, 0xb6, 0x91, 0x97, 0xad, 0xf2, 0x90, 0x3a, 0x80, 0xce, 0x03, 0x71,
+ 0xaf, 0x8a, 0x8b, 0x7e, 0x1f, 0xcb, 0xbd, 0x01, 0x4e, 0x37, 0xc5, 0x7f,
+ 0x84, 0xe8, 0xe5, 0xd8, 0x9f, 0xfa, 0x27, 0xf7, 0xd8, 0xea, 0x47, 0xd7,
+ 0x29, 0x9d, 0xbf, 0xd3, 0xd1, 0xdf, 0x75, 0x3f, 0x30, 0xce, 0x1d, 0x15,
+ 0x27, 0xa9, 0x0f, 0x3b, 0xe8, 0xff, 0xa6, 0xf4, 0xd3, 0x7e, 0xf9, 0xfc,
+ 0xd7, 0xcd, 0xf3, 0xd6, 0xa0, 0xba, 0x15, 0x8d, 0xba, 0xfd, 0x28, 0x75,
+ 0x9b, 0x81, 0x17, 0xad, 0x80, 0xf4, 0x0a, 0x80, 0xb8, 0x5f, 0x25, 0x80,
+ 0xf8, 0xbc, 0xe0, 0x45, 0xc1, 0xcf, 0x04, 0x97, 0x05, 0xf7, 0x0a, 0x0e,
+ 0x0b, 0xee, 0x11, 0x7c, 0x4e, 0xf0, 0x6f, 0xc1, 0x9a, 0xa0, 0x2f, 0x58,
+ 0x15, 0xbc, 0x27, 0xe8, 0x09, 0x96, 0x0d, 0x7f, 0x75, 0xc1, 0x92, 0x60,
+ 0x24, 0xf8, 0x9a, 0x61, 0xef, 0xe6, 0x18, 0x57, 0x45, 0x3e, 0x28, 0xf2,
+ 0x49, 0x91, 0xb1, 0xa0, 0x32, 0xf7, 0xa9, 0x7a, 0x7d, 0xbe, 0xd1, 0xdf,
+ 0xd5, 0x9e, 0x7c, 0x6f, 0x69, 0xbd, 0x12, 0xd5, 0x0f, 0xda, 0x49, 0xfd,
+ 0x8f, 0xb7, 0xd1, 0x67, 0xb5, 0xe9, 0xd6, 0x20, 0xbb, 0x1b, 0x31, 0xe7,
+ 0xf1, 0x91, 0xd8, 0x07, 0xfd, 0xef, 0x32, 0xf6, 0x68, 0xaa, 0x63, 0xce,
+ 0xd7, 0xa0, 0x3d, 0x7a, 0x45, 0xf6, 0xe8, 0xd0, 0x96, 0xf9, 0xe5, 0x39,
+ 0x3d, 0x2a, 0xf6, 0x53, 0x32, 0x9f, 0x8d, 0x0c, 0xbd, 0x30, 0xb1, 0xaf,
+ 0x14, 0x2f, 0x63, 0x1f, 0x6e, 0xe6, 0xba, 0x1d, 0x8c, 0x5b, 0x94, 0xb8,
+ 0x59, 0xf9, 0xa1, 0xbd, 0xcc, 0x6f, 0x4b, 0xcf, 0x71, 0x7a, 0x7e, 0x79,
+ 0x0e, 0x6d, 0x63, 0x0e, 0x2f, 0xed, 0xd0, 0x87, 0xb2, 0x51, 0xcf, 0xf3,
+ 0x4a, 0x9f, 0x45, 0xcb, 0x62, 0x5c, 0x62, 0xec, 0x78, 0x76, 0x01, 0xf1,
+ 0x90, 0xf7, 0x0b, 0xfb, 0x1b, 0xa5, 0x7b, 0x78, 0xc1, 0x02, 0xed, 0x6d,
+ 0x01, 0x16, 0xec, 0x21, 0x85, 0x4f, 0xe3, 0x0f, 0x59, 0xaf, 0x5e, 0xbc,
+ 0x4d, 0x18, 0x2c, 0xdd, 0x62, 0xfd, 0x3f, 0x9a, 0x9c, 0xf7, 0x1b, 0xe3,
+ 0x60, 0xfc, 0xf4, 0x77, 0xd9, 0x77, 0x1f, 0xe5, 0x7f, 0x73, 0x61, 0xa4,
+ 0xe3, 0x88, 0xdd, 0x79, 0xbd, 0x47, 0xfc, 0xbb, 0x62, 0xd7, 0xa8, 0x6e,
+ 0xef, 0x47, 0x24, 0x0e, 0x7b, 0xf3, 0xcc, 0xaf, 0x1f, 0x44, 0xfa, 0x3e,
+ 0xc2, 0x2b, 0x6d, 0xb6, 0xab, 0x50, 0x9c, 0x3d, 0xfd, 0x65, 0x63, 0x3e,
+ 0x9a, 0xbb, 0xe2, 0xd7, 0x27, 0xf1, 0x26, 0xbf, 0x26, 0xef, 0xaf, 0xf9,
+ 0xb5, 0x04, 0x67, 0x66, 0x7c, 0x8a, 0x57, 0xb5, 0xd9, 0xcd, 0x9b, 0x3e,
+ 0xe3, 0xdb, 0x2e, 0xe3, 0x43, 0x17, 0xeb, 0x13, 0xc7, 0xe7, 0xca, 0x2c,
+ 0x9f, 0xad, 0xe8, 0xbd, 0xd6, 0xf6, 0x3a, 0xaf, 0xed, 0xf2, 0xc1, 0xf8,
+ 0x3a, 0x8e, 0xce, 0x43, 0xc7, 0x4b, 0xcf, 0x43, 0x76, 0x5c, 0xc6, 0xae,
+ 0x95, 0xae, 0xc3, 0xd2, 0x04, 0x63, 0x61, 0x12, 0xf3, 0xfa, 0x21, 0xde,
+ 0xd8, 0xeb, 0x56, 0x8d, 0xf4, 0xc6, 0x80, 0xe5, 0x59, 0x99, 0xbf, 0x59,
+ 0xda, 0x47, 0xc5, 0x37, 0x16, 0x62, 0x1d, 0x42, 0x7a, 0x6f, 0x2c, 0xf7,
+ 0x67, 0x9a, 0x87, 0xbc, 0x9c, 0xab, 0xfa, 0x8f, 0xa5, 0xf7, 0x78, 0x8d,
+ 0xe7, 0xad, 0x94, 0x9e, 0xd3, 0x46, 0x3c, 0x78, 0xfe, 0xdd, 0xfe, 0x72,
+ 0x6f, 0x50, 0x3f, 0x74, 0x7e, 0x01, 0x74, 0x27, 0xb3, 0xde, 0x09, 0xfd,
+ 0x3e, 0x6b, 0x9e, 0xa4, 0xe3, 0x7e, 0x98, 0x4f, 0xdd, 0xfb, 0x28, 0x74,
+ 0x06, 0xf9, 0xff, 0x46, 0xbf, 0x7b, 0x03, 0xf6, 0x76, 0xa7, 0xb8, 0x29,
+ 0xff, 0x55, 0xb5, 0x39, 0xb0, 0x75, 0xef, 0x1c, 0x63, 0x4f, 0x9f, 0xae,
+ 0xf3, 0x9e, 0x36, 0xb6, 0xcc, 0xa7, 0xe6, 0xaf, 0xe6, 0xb6, 0xfc, 0xf5,
+ 0xac, 0xf8, 0xca, 0x02, 0xe6, 0x2b, 0x7c, 0x4f, 0xd2, 0x79, 0x3a, 0xfa,
+ 0x9e, 0x06, 0x2f, 0xf1, 0xfd, 0xee, 0xaf, 0xef, 0x8e, 0xdf, 0x92, 0x75,
+ 0x1a, 0xc4, 0x6f, 0xae, 0xc1, 0x57, 0xbf, 0xaf, 0x6f, 0xf2, 0x1b, 0x7e,
+ 0x5f, 0x59, 0xe1, 0xfe, 0xbd, 0x97, 0x98, 0xdf, 0x64, 0xdd, 0x87, 0xa4,
+ 0xee, 0x4a, 0x8f, 0xec, 0x6f, 0x1b, 0xf6, 0xba, 0xff, 0xef, 0x08, 0x6f,
+ 0x5a, 0x53, 0x3c, 0x7f, 0x4e, 0xf7, 0x91, 0xd1, 0x97, 0xc9, 0x0e, 0xee,
+ 0xd5, 0x65, 0x88, 0xa4, 0x6e, 0x77, 0x53, 0xf5, 0xab, 0x08, 0x4f, 0x38,
+ 0xf0, 0x55, 0xa4, 0xeb, 0xac, 0xfb, 0xc8, 0xf8, 0x25, 0xe9, 0xd7, 0x76,
+ 0xa8, 0x77, 0x0d, 0xbe, 0xd8, 0xe0, 0x41, 0x9f, 0xfc, 0x4d, 0x08, 0xaf,
+ 0x9c, 0x91, 0xfd, 0xfe, 0xcb, 0x65, 0xfe, 0xe8, 0x1e, 0xa3, 0x3d, 0x87,
+ 0x11, 0xd9, 0xf3, 0x6e, 0x85, 0xe5, 0x7a, 0x85, 0x79, 0x71, 0xc2, 0xf1,
+ 0x48, 0xaf, 0x5e, 0x61, 0x1c, 0x29, 0xa3, 0x5d, 0x00, 0x0f, 0x8e, 0x93,
+ 0x7a, 0x67, 0xd1, 0x63, 0x7e, 0x5f, 0xbc, 0x25, 0xfc, 0xe3, 0xeb, 0xfa,
+ 0xc9, 0x7d, 0x5f, 0xc6, 0xf3, 0x11, 0xb5, 0xcf, 0xc9, 0x7e, 0x28, 0x9d,
+ 0x36, 0xe7, 0xf7, 0xa9, 0x64, 0xdf, 0xf4, 0x93, 0xf5, 0xd6, 0xf3, 0xbd,
+ 0x9c, 0xd1, 0xa7, 0x99, 0x58, 0xf3, 0xdf, 0xd8, 0x0c, 0xe6, 0xeb, 0x43,
+ 0xd5, 0xe1, 0xf9, 0x60, 0x54, 0x7e, 0x2c, 0x07, 0xcd, 0x1a, 0x73, 0xc2,
+ 0x27, 0x73, 0x57, 0xc8, 0xcd, 0xf1, 0x39, 0x7d, 0x3e, 0x4d, 0x0b, 0x32,
+ 0xbb, 0xf2, 0x13, 0x9d, 0x57, 0xa3, 0x3c, 0x9f, 0x3b, 0xc7, 0x74, 0xbd,
+ 0x7c, 0xba, 0xff, 0x02, 0xd7, 0xeb, 0xad, 0x1b, 0x8c, 0xa7, 0xe0, 0x75,
+ 0x42, 0x77, 0xc1, 0x63, 0x7e, 0x5c, 0xf4, 0x4a, 0x84, 0x40, 0xf5, 0xb2,
+ 0x5e, 0xe2, 0x77, 0xad, 0x28, 0xef, 0xd1, 0x50, 0xa2, 0x8f, 0xe6, 0xfb,
+ 0xb1, 0xdb, 0x7e, 0x26, 0xf9, 0x54, 0xbf, 0x6b, 0x39, 0xe3, 0xef, 0xc8,
+ 0x8a, 0x31, 0x9f, 0xef, 0x66, 0xcc, 0x67, 0x33, 0x63, 0xbe, 0x4d, 0x5e,
+ 0xb9, 0x24, 0x7b, 0x57, 0x80, 0x62, 0x9e, 0x1e, 0x26, 0xaf, 0x70, 0x95,
+ 0xfa, 0x6b, 0xcd, 0xf1, 0xbb, 0xee, 0x15, 0xe7, 0x73, 0x54, 0x37, 0x6f,
+ 0x9e, 0xf5, 0x0a, 0x7c, 0x1e, 0x68, 0xbc, 0x7e, 0x95, 0xdf, 0x4f, 0x0b,
+ 0xfe, 0x07, 0x89, 0x6e, 0x1e, 0x13, 0x00, 0x0d, 0x00, 0x00, 0x00 };
static u8 bnx2_xi_rv2p_proc2[] = {
- /* Date: 01/14/2008 15:44 */
- 0xad, 0x58, 0x5d, 0x6c, 0xd3, 0x55, 0x14, 0xbf, 0xfd, 0x58, 0xdb, 0x75,
- 0xff, 0xb6, 0x63, 0x9b, 0xdd, 0xa7, 0x6e, 0x6e, 0x61, 0x6c, 0xd8, 0xcd,
- 0xd1, 0x8d, 0x4f, 0x4d, 0x5c, 0x86, 0x19, 0x20, 0x26, 0x8c, 0x61, 0xd4,
- 0x37, 0xd8, 0x90, 0xb2, 0xb2, 0x8d, 0x2c, 0x8c, 0xf0, 0xc0, 0x8b, 0x0d,
- 0xd3, 0xf1, 0xd2, 0x07, 0x47, 0xb2, 0x0d, 0x8d, 0xc1, 0x45, 0x7d, 0x40,
- 0x9f, 0xec, 0x83, 0x52, 0x30, 0xc6, 0xc4, 0xe8, 0x42, 0xf0, 0x01, 0x48,
- 0x30, 0xc6, 0x68, 0x48, 0x08, 0xea, 0x32, 0x10, 0x75, 0x0c, 0xfb, 0x64,
- 0x98, 0xf7, 0x9e, 0xdf, 0xb9, 0xff, 0xfe, 0xff, 0x5d, 0x27, 0x18, 0xec,
- 0x43, 0x4f, 0xef, 0xbd, 0xe7, 0x9e, 0x7b, 0x3e, 0x7e, 0xe7, 0x9c, 0x7b,
- 0x5b, 0x2c, 0x84, 0x70, 0x8a, 0x44, 0xaa, 0x56, 0x52, 0x61, 0x38, 0x5c,
- 0x02, 0x9f, 0xb5, 0xc5, 0x44, 0xae, 0xa5, 0x7c, 0xf2, 0xbb, 0x40, 0xbc,
- 0xe4, 0xac, 0xa0, 0xb1, 0x5b, 0x28, 0x1a, 0x12, 0x22, 0x61, 0xa5, 0xa5,
- 0x4c, 0xaf, 0x32, 0xfd, 0x9d, 0xe9, 0xe3, 0x0e, 0xd0, 0x2b, 0x3c, 0xde,
- 0xc2, 0xe3, 0x6b, 0x3c, 0xfe, 0x91, 0xe9, 0x46, 0x9e, 0xdf, 0xcc, 0x34,
- 0xc9, 0x74, 0x3b, 0xaf, 0xa7, 0x99, 0xca, 0x4f, 0xc2, 0x90, 0x5f, 0x72,
- 0xb9, 0x59, 0xeb, 0x69, 0x60, 0xba, 0x19, 0xfa, 0xee, 0xa9, 0x53, 0x7c,
- 0xf3, 0x4b, 0x59, 0x3e, 0xcc, 0x5f, 0x9f, 0x00, 0xad, 0xc5, 0xae, 0x8f,
- 0x13, 0x4f, 0xeb, 0xfd, 0x20, 0x7d, 0x01, 0xd0, 0x7e, 0xb6, 0xbf, 0x33,
- 0x42, 0x24, 0xb9, 0xdf, 0x89, 0x71, 0x77, 0xa3, 0xf2, 0x43, 0x89, 0x70,
- 0x3b, 0x95, 0x9c, 0x56, 0x9f, 0xe7, 0x3c, 0xe6, 0x5f, 0x0d, 0x81, 0xbe,
- 0xe6, 0x07, 0xfd, 0xc5, 0x5f, 0x28, 0xbf, 0x97, 0x96, 0x62, 0x45, 0x2c,
- 0xdf, 0x60, 0xb5, 0x8b, 0xb0, 0x7f, 0xd6, 0x80, 0x1e, 0x2f, 0xd7, 0x41,
- 0xbf, 0xef, 0x9f, 0x52, 0xf3, 0x2e, 0x91, 0x60, 0x39, 0x42, 0x68, 0x3d,
- 0x79, 0x7d, 0x10, 0xfb, 0x56, 0xad, 0xc1, 0xea, 0x5b, 0x31, 0x8c, 0xab,
- 0x3f, 0x28, 0xa6, 0xb8, 0x9c, 0x4e, 0x69, 0xfe, 0x7c, 0x72, 0xdd, 0x52,
- 0x2e, 0xe4, 0x8b, 0x7a, 0x1f, 0x29, 0x93, 0x88, 0x80, 0x8a, 0x96, 0xdc,
- 0x73, 0x20, 0x7f, 0x6a, 0xb5, 0x9a, 0x77, 0x8a, 0x5e, 0x97, 0x9a, 0xf7,
- 0x88, 0xde, 0xb8, 0xf6, 0x2f, 0xd6, 0x63, 0x1e, 0x22, 0x15, 0x7d, 0xe3,
- 0xca, 0xce, 0x90, 0xd8, 0xe7, 0x0c, 0x11, 0x3f, 0xfc, 0xe2, 0xf2, 0x19,
- 0x9f, 0x81, 0xff, 0xcb, 0x5a, 0x83, 0x6c, 0x89, 0xb5, 0x63, 0x5f, 0x59,
- 0x14, 0x74, 0x32, 0x5a, 0xa0, 0x48, 0x24, 0x36, 0x4a, 0xc3, 0xd6, 0x9b,
- 0xeb, 0x7c, 0xc4, 0x97, 0x68, 0xd1, 0xf1, 0xd3, 0xf1, 0x52, 0x71, 0xfc,
- 0x44, 0xc6, 0x91, 0xdd, 0xd2, 0x00, 0xbf, 0xfe, 0xba, 0x5a, 0xf1, 0x4b,
- 0xe7, 0xd6, 0xe3, 0x9c, 0xac, 0x7e, 0xd6, 0xf8, 0x7f, 0xf4, 0x1f, 0xe2,
- 0xaf, 0xe4, 0x75, 0xb2, 0x5f, 0xea, 0xa4, 0x5f, 0x14, 0xad, 0x71, 0x24,
- 0x5a, 0xec, 0xf1, 0xb8, 0x3e, 0x11, 0xa2, 0xdf, 0xb7, 0xba, 0x8a, 0xc9,
- 0xaf, 0xbb, 0x30, 0x7f, 0xaa, 0xfb, 0x1c, 0xe2, 0xb1, 0x83, 0xec, 0x17,
- 0xfe, 0x37, 0x3e, 0xc5, 0xae, 0xbe, 0x80, 0x1a, 0xbf, 0xd2, 0x11, 0xbb,
- 0x80, 0xf5, 0x82, 0x31, 0xf8, 0x75, 0x17, 0x4b, 0xdd, 0xe1, 0x72, 0x28,
- 0x92, 0xf4, 0x8c, 0xd1, 0xd0, 0x98, 0xa5, 0x75, 0x43, 0x9c, 0x4c, 0x61,
- 0xfd, 0x70, 0x91, 0x1a, 0xef, 0x8a, 0xcc, 0x63, 0x1c, 0x89, 0x8f, 0xf3,
- 0x46, 0x27, 0xfc, 0x70, 0xcb, 0x09, 0x79, 0x0c, 0x2f, 0xbf, 0x9b, 0xe2,
- 0xe0, 0x10, 0x46, 0x37, 0xe8, 0x9b, 0xb4, 0xfe, 0xb7, 0x23, 0x49, 0x76,
- 0x77, 0x07, 0xdd, 0xe7, 0xc0, 0xc8, 0xb8, 0x36, 0x71, 0xab, 0x71, 0xff,
- 0xb0, 0xf8, 0x1d, 0x37, 0x34, 0x5e, 0xd9, 0xff, 0xec, 0xdf, 0xf7, 0x44,
- 0x2e, 0x4e, 0x41, 0xbb, 0x1b, 0x41, 0x3d, 0x0d, 0xb9, 0x78, 0xd5, 0xf8,
- 0xb4, 0xfb, 0x99, 0xe3, 0x63, 0xc1, 0x0b, 0x11, 0x89, 0x13, 0x1b, 0x6e,
- 0x18, 0xa7, 0x95, 0xd2, 0x5f, 0x3a, 0xfe, 0x4a, 0x90, 0x57, 0x0c, 0xb2,
- 0xbc, 0x38, 0xdb, 0x35, 0xc4, 0x76, 0xdd, 0xf1, 0x6b, 0xbf, 0x6a, 0x7b,
- 0x40, 0x4f, 0xda, 0xec, 0x71, 0x48, 0x3c, 0xd9, 0x71, 0xc8, 0xfa, 0x24,
- 0xbf, 0xa9, 0xc7, 0x8f, 0xea, 0x06, 0x50, 0xd3, 0xce, 0x46, 0xc5, 0xe7,
- 0x89, 0x4e, 0xa7, 0xec, 0x38, 0xd4, 0xf9, 0xb8, 0xa7, 0x4e, 0xcb, 0x57,
- 0xb8, 0xcc, 0x48, 0x5c, 0x22, 0x6e, 0xa7, 0x53, 0xd6, 0xfc, 0xac, 0xca,
- 0x93, 0x9f, 0xf6, 0xbc, 0xd0, 0x7e, 0x39, 0x1c, 0xa0, 0x02, 0xd5, 0x71,
- 0x79, 0xce, 0x7e, 0x1e, 0xf0, 0xed, 0x35, 0xf1, 0x53, 0xb6, 0x81, 0xfd,
- 0xc7, 0x34, 0xbc, 0x51, 0xc9, 0xeb, 0x61, 0xf9, 0x6d, 0x2c, 0xdf, 0xb0,
- 0xe4, 0x9d, 0xd2, 0xaf, 0xcb, 0xcc, 0x37, 0x1d, 0xb7, 0x6c, 0xde, 0x69,
- 0xff, 0xd1, 0xf9, 0x91, 0xcb, 0x73, 0x6a, 0x7f, 0xf5, 0x03, 0xf2, 0x70,
- 0x93, 0x29, 0xef, 0x3b, 0x33, 0xdf, 0xd4, 0x7a, 0x91, 0x78, 0x8e, 0x87,
- 0xf6, 0x7a, 0xf2, 0xa7, 0xac, 0x27, 0x64, 0x87, 0xcf, 0x38, 0xc7, 0xf5,
- 0x63, 0x54, 0x9d, 0x53, 0xc1, 0x7a, 0x57, 0xb0, 0xde, 0xb2, 0x5f, 0xb5,
- 0x70, 0x9d, 0xd9, 0x6b, 0xad, 0x17, 0x6b, 0x2d, 0x79, 0xaf, 0xc6, 0x4d,
- 0x4b, 0xcb, 0xfb, 0x85, 0xcd, 0x9f, 0x09, 0x41, 0xfe, 0xf7, 0x72, 0x7c,
- 0x3c, 0x79, 0xfa, 0x8b, 0xe6, 0x07, 0xbe, 0xb6, 0x11, 0xbf, 0xcf, 0xc4,
- 0xbf, 0xdd, 0xde, 0xaa, 0x3c, 0x75, 0x27, 0xd7, 0x7e, 0xf8, 0xb3, 0xcf,
- 0x19, 0x20, 0xbe, 0x1b, 0x23, 0x6a, 0xdf, 0x49, 0x87, 0xf6, 0x53, 0x27,
- 0xea, 0x90, 0x03, 0xf6, 0xd6, 0xb0, 0xbd, 0x72, 0xb9, 0x85, 0xf0, 0xef,
- 0xbb, 0x31, 0x62, 0xb5, 0xd7, 0xf8, 0x97, 0xf3, 0xec, 0xb8, 0x19, 0xe1,
- 0x3e, 0xd6, 0x8f, 0xbc, 0xf0, 0xed, 0xff, 0x5c, 0xeb, 0xc3, 0xe7, 0x86,
- 0xf4, 0xf9, 0x4a, 0x5e, 0xb5, 0x98, 0x1b, 0x55, 0xfb, 0x1f, 0x13, 0x0c,
- 0x33, 0x31, 0xdc, 0x84, 0xfa, 0x77, 0xe7, 0x00, 0xf4, 0x1f, 0x6e, 0xd4,
- 0x7d, 0x1c, 0x38, 0x16, 0x5c, 0xff, 0xbf, 0x9e, 0xc8, 0xe7, 0x97, 0x41,
- 0x07, 0xf8, 0xca, 0xd8, 0xae, 0x62, 0xb6, 0x2b, 0x22, 0x72, 0xeb, 0xec,
- 0x5e, 0xca, 0x97, 0x4e, 0xe6, 0x7b, 0x56, 0xd7, 0xe3, 0x65, 0x7c, 0xb0,
- 0xbf, 0x80, 0xcf, 0xcf, 0xe7, 0xaf, 0x7c, 0x72, 0xd3, 0x8c, 0xa3, 0x01,
- 0xe6, 0x73, 0xe7, 0xa9, 0xf3, 0x18, 0x65, 0xd6, 0x50, 0x9d, 0x3f, 0x73,
- 0x3c, 0xad, 0xf8, 0x02, 0x26, 0xce, 0xed, 0x76, 0xfd, 0x74, 0xff, 0xd1,
- 0xfd, 0xaf, 0xf8, 0xc2, 0xe2, 0x60, 0x70, 0x25, 0x3f, 0xbb, 0xd5, 0xf4,
- 0xcc, 0x42, 0x5a, 0xc7, 0xc9, 0x20, 0x3b, 0xe7, 0x46, 0xd5, 0xf9, 0x1f,
- 0xe6, 0xf8, 0xdf, 0x69, 0xf1, 0x3f, 0xf8, 0x9f, 0x88, 0x3c, 0xaa, 0xdf,
- 0xf3, 0xf5, 0xe5, 0x2f, 0xee, 0x2f, 0xcf, 0x13, 0x35, 0x7f, 0xe1, 0xa1,
- 0xfd, 0xb1, 0xbb, 0xdd, 0x6a, 0x7f, 0x83, 0x98, 0x4d, 0x21, 0xbf, 0x7a,
- 0x18, 0x87, 0xfb, 0xb8, 0x5e, 0xdf, 0xf0, 0xab, 0x09, 0x9f, 0xe8, 0xdf,
- 0x49, 0xfe, 0x10, 0xe1, 0x22, 0xf8, 0xa7, 0xff, 0x45, 0xed, 0x4f, 0xcc,
- 0x57, 0x51, 0xbf, 0x75, 0x89, 0x1e, 0xaf, 0x41, 0xfc, 0x55, 0x01, 0xd0,
- 0x30, 0xd7, 0xf9, 0x59, 0xb3, 0x8f, 0x81, 0x9e, 0xf6, 0xe8, 0xba, 0x8c,
- 0x7e, 0xfe, 0x95, 0x47, 0x31, 0xc8, 0x20, 0x35, 0xa3, 0x3e, 0x77, 0x35,
- 0x1a, 0xb4, 0xde, 0xdb, 0x0c, 0x3c, 0x89, 0x7a, 0xdd, 0xe7, 0xf0, 0xe1,
- 0x3e, 0x50, 0x95, 0xed, 0x77, 0xd6, 0x7e, 0x58, 0x68, 0xe9, 0x07, 0xfa,
- 0x3c, 0xed, 0x47, 0x2d, 0x97, 0x86, 0xb2, 0xaf, 0x58, 0xfb, 0xa1, 0xee,
- 0x13, 0x8b, 0xdc, 0x27, 0x4a, 0xc5, 0xc5, 0x14, 0xec, 0x9a, 0x4d, 0xe5,
- 0xe2, 0x4f, 0x9f, 0xa7, 0xe5, 0x41, 0x6f, 0x6d, 0x47, 0x56, 0x3e, 0xce,
- 0x3f, 0xc0, 0x7a, 0xfe, 0x4c, 0xf7, 0xd8, 0x30, 0xdb, 0xa3, 0xe4, 0x62,
- 0x7e, 0x3b, 0xf7, 0xe7, 0x84, 0x39, 0xb6, 0xf7, 0xd5, 0x1e, 0xd2, 0xab,
- 0x84, 0xf1, 0x16, 0xb6, 0xe4, 0x03, 0xf8, 0xcb, 0xda, 0x40, 0x27, 0xdb,
- 0x74, 0x1c, 0x74, 0xbc, 0x74, 0x7c, 0x10, 0xc7, 0xf0, 0x3a, 0x62, 0xeb,
- 0xe8, 0x5f, 0x47, 0x7d, 0xa4, 0xad, 0x7f, 0x41, 0xe3, 0x0f, 0xfb, 0x77,
- 0x47, 0x14, 0xff, 0xeb, 0xe2, 0x2a, 0xe1, 0x50, 0x88, 0x1f, 0x98, 0x66,
- 0xfb, 0x15, 0x07, 0xc0, 0xcc, 0x57, 0x8e, 0x5f, 0x01, 0x4f, 0xb7, 0xeb,
- 0x7a, 0xae, 0xe3, 0x65, 0xcd, 0xd7, 0xd8, 0x32, 0xdc, 0x66, 0xeb, 0xb2,
- 0xb6, 0x53, 0xf1, 0x47, 0x18, 0x8f, 0x3e, 0xd1, 0xb5, 0x0d, 0xf7, 0xdc,
- 0xa0, 0x17, 0x75, 0x3f, 0xe8, 0xb5, 0xc6, 0x4b, 0xe2, 0xa2, 0xd0, 0xab,
- 0x86, 0x35, 0x25, 0x85, 0x64, 0xcf, 0xa9, 0x4b, 0xdf, 0xd2, 0xf2, 0xfb,
- 0xd3, 0x45, 0x98, 0x2f, 0xdf, 0x19, 0x22, 0x7f, 0x4c, 0x01, 0xcf, 0xef,
- 0x4e, 0x82, 0xbe, 0x23, 0x5e, 0xc0, 0xfe, 0x92, 0x13, 0x74, 0x0f, 0xf4,
- 0x95, 0x33, 0x3e, 0x2b, 0x50, 0x27, 0x92, 0xd3, 0x74, 0x2f, 0x59, 0x5a,
- 0x12, 0x01, 0x45, 0x3d, 0x66, 0xbf, 0x01, 0x3e, 0xdd, 0x96, 0x38, 0x3f,
- 0x08, 0xaf, 0x74, 0xaf, 0x94, 0x78, 0xc4, 0x76, 0xc6, 0xad, 0x2f, 0x17,
- 0xb7, 0xda, 0x1f, 0x15, 0xce, 0xbc, 0x38, 0xdd, 0x60, 0xc7, 0xa9, 0x87,
- 0x71, 0x7a, 0xcf, 0xec, 0xef, 0xcb, 0xe5, 0xa2, 0xcf, 0x5f, 0xfc, 0xdf,
- 0x70, 0x0b, 0xba, 0xbd, 0x41, 0x9d, 0x5f, 0xbe, 0xac, 0x1e, 0xd7, 0xda,
- 0xe2, 0xdc, 0x7c, 0x5f, 0xeb, 0x75, 0xc2, 0x63, 0x5d, 0x6f, 0x31, 0xfb,
- 0xd9, 0x11, 0x7e, 0xe7, 0x65, 0x0c, 0xfa, 0x11, 0xbd, 0x93, 0xa4, 0xa1,
- 0x51, 0x79, 0x56, 0xf1, 0x35, 0x45, 0x8f, 0x70, 0xbd, 0xbd, 0xe4, 0x42,
- 0xbd, 0x19, 0x38, 0x80, 0xf1, 0x65, 0xae, 0x1f, 0x77, 0xd7, 0x50, 0x5d,
- 0x8e, 0x1e, 0x39, 0xaf, 0xe5, 0x91, 0x1c, 0x23, 0xc3, 0x75, 0xfd, 0x79,
- 0x17, 0xd7, 0x5b, 0xf2, 0x9b, 0x3b, 0xfa, 0x07, 0xdd, 0x67, 0xdc, 0xa2,
- 0xeb, 0x49, 0x45, 0x2b, 0x65, 0xfd, 0xe6, 0xf3, 0x9f, 0x01, 0xed, 0xf5,
- 0x82, 0x8a, 0x66, 0x7b, 0x3c, 0x84, 0x69, 0x17, 0x46, 0x9e, 0x7a, 0x96,
- 0xd3, 0x87, 0xb1, 0x97, 0xef, 0x65, 0xd3, 0xec, 0xa7, 0x20, 0xf9, 0xa3,
- 0x58, 0xda, 0xa9, 0x68, 0x28, 0x3a, 0x9a, 0x86, 0xfe, 0x43, 0x5b, 0x61,
- 0xdf, 0x22, 0xdb, 0xcd, 0x34, 0xf8, 0xf6, 0x18, 0xe1, 0x2f, 0x38, 0x8e,
- 0x77, 0x48, 0xd0, 0x33, 0x06, 0x3b, 0x86, 0x32, 0x18, 0x2f, 0x6e, 0x06,
- 0xfd, 0x6b, 0x0b, 0xf6, 0x1d, 0x3d, 0xce, 0xfe, 0xd8, 0x9a, 0x7f, 0xdf,
- 0xc0, 0x3d, 0xf0, 0x0d, 0x37, 0xa9, 0xf3, 0x07, 0x67, 0xf8, 0xfd, 0x22,
- 0xe2, 0x2e, 0x35, 0x8e, 0x1b, 0x19, 0x1e, 0x1f, 0xe2, 0xfa, 0x7e, 0x9b,
- 0xdf, 0x1b, 0x43, 0x39, 0xef, 0x8d, 0x79, 0xdc, 0x33, 0x67, 0x32, 0x49,
- 0xe0, 0x22, 0x51, 0x98, 0xfb, 0x5e, 0x55, 0xe3, 0x9a, 0x68, 0x39, 0xc7,
- 0xa9, 0x6c, 0x3d, 0xe8, 0xe4, 0x7a, 0xbc, 0x13, 0x86, 0x8e, 0xb1, 0x5f,
- 0x3a, 0x28, 0x4e, 0xad, 0x0b, 0xe9, 0x95, 0xde, 0xc9, 0xe0, 0x9b, 0xe2,
- 0x73, 0xc3, 0xdc, 0x4f, 0xc2, 0xc8, 0x3f, 0x51, 0x91, 0xe4, 0x77, 0xcb,
- 0x04, 0xee, 0x9d, 0x53, 0x06, 0x68, 0x38, 0xa0, 0xf5, 0x45, 0x3e, 0x26,
- 0x52, 0xc8, 0x3b, 0xac, 0x3b, 0x2c, 0xeb, 0x7c, 0x1f, 0x59, 0xf6, 0xce,
- 0x51, 0x74, 0xd1, 0x51, 0xea, 0xd0, 0x76, 0x62, 0xb5, 0x3f, 0xa0, 0xf0,
- 0x7b, 0xd3, 0xcc, 0xab, 0x79, 0xf2, 0x5b, 0xf5, 0x4c, 0x86, 0xf4, 0xaf,
- 0x12, 0xa5, 0xd4, 0x87, 0x2b, 0x83, 0x0b, 0xf0, 0x63, 0x74, 0x9a, 0xfd,
- 0x3f, 0xb2, 0x09, 0xf4, 0x18, 0xe3, 0x4f, 0xe3, 0xea, 0xca, 0x46, 0x83,
- 0xf6, 0xcd, 0x8d, 0xe2, 0x1c, 0x7d, 0x8f, 0xc8, 0x7d, 0x8f, 0x6b, 0x3c,
- 0x56, 0xb6, 0xa3, 0x90, 0x0e, 0x1c, 0x55, 0xe7, 0x04, 0x24, 0x8e, 0x94,
- 0xfe, 0xd2, 0x27, 0x9c, 0x8f, 0x76, 0x9c, 0x2a, 0x1c, 0xeb, 0xfc, 0xb0,
- 0xe2, 0x3b, 0x37, 0xdf, 0xb3, 0x78, 0x0d, 0xd2, 0xbd, 0x5c, 0x16, 0xb9,
- 0x04, 0xbf, 0x9b, 0xf8, 0x7e, 0xb0, 0x52, 0xfc, 0xde, 0x46, 0xfc, 0xa2,
- 0xac, 0xb7, 0x11, 0x1f, 0x43, 0x5f, 0x1c, 0x67, 0x1c, 0xcd, 0x37, 0xf1,
- 0xfd, 0x87, 0xf5, 0xfb, 0x8d, 0xdf, 0x67, 0xc0, 0x9b, 0xd7, 0x88, 0xa5,
- 0x19, 0x5f, 0x8c, 0xfb, 0x43, 0x6c, 0xf7, 0x6d, 0xd8, 0x6d, 0x68, 0xbb,
- 0xe3, 0xa6, 0xdd, 0xfa, 0x7e, 0x65, 0x95, 0x53, 0x22, 0x71, 0xab, 0xe8,
- 0x2a, 0xe3, 0x0a, 0xd5, 0xb3, 0x02, 0xb6, 0x53, 0xf2, 0xb5, 0x2b, 0x7b,
- 0x82, 0x6c, 0x4f, 0x40, 0x1c, 0x6c, 0xb5, 0xee, 0x2b, 0xe2, 0x7d, 0x7e,
- 0xb9, 0x0f, 0xf3, 0xa8, 0x0b, 0xc6, 0x0a, 0xfe, 0x54, 0x7e, 0xd3, 0x72,
- 0x73, 0xf3, 0xde, 0xea, 0x3f, 0xba, 0x91, 0xd2, 0x07, 0xf5, 0x4d, 0xc6,
- 0xa9, 0x05, 0xff, 0x1f, 0xe8, 0xfa, 0x76, 0x97, 0xee, 0xaf, 0xfe, 0x33,
- 0xc3, 0xa8, 0x4f, 0x67, 0x86, 0xcf, 0xf2, 0xbb, 0x83, 0xfd, 0xd2, 0x43,
- 0xff, 0x5b, 0xc8, 0xd8, 0xd5, 0xdb, 0xeb, 0x9b, 0x5d, 0x8f, 0x6a, 0x8b,
- 0x1e, 0xfa, 0xdc, 0x7f, 0x00, 0x5a, 0x33, 0xe6, 0xc0, 0x30, 0x14, 0x00,
- 0x00, 0x00 };
+ /* Date: 04/25/2008 22:02 */
+#define XI_RV2P_PROC2_MAX_BD_PAGE_LOC 5
+#define XI_RV2P_PROC2_BD_PAGE_SIZE_MSK 0xffff
+#define XI_RV2P_PROC2_BD_PAGE_SIZE ((PAGE_SIZE / 16) - 1)
+ 0xad, 0x58, 0x5b, 0x6c, 0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0xed,
+ 0xcc, 0x9d, 0x99, 0xd2, 0xd6, 0xe9, 0x8b, 0x48, 0x69, 0xa5, 0x74, 0x70,
+ 0x0a, 0x65, 0x5a, 0x1e, 0x3e, 0x12, 0x49, 0xd1, 0x02, 0x3e, 0x42, 0xa9,
+ 0x86, 0x98, 0x18, 0x03, 0x9d, 0x4a, 0xe9, 0x40, 0x4b, 0x2a, 0x25, 0x7c,
+ 0xf0, 0xe3, 0x84, 0x62, 0xf9, 0x99, 0x44, 0x4b, 0x80, 0x16, 0x63, 0x48,
+ 0x23, 0x3f, 0xc4, 0xbf, 0x26, 0x28, 0x45, 0x3f, 0x4c, 0x88, 0x36, 0x04,
+ 0x3e, 0xc0, 0x44, 0x63, 0xfc, 0x21, 0x12, 0xc4, 0x5a, 0xa0, 0xc1, 0x82,
+ 0x36, 0xc6, 0x48, 0xeb, 0x3d, 0x7b, 0xed, 0x73, 0xe7, 0xde, 0xe9, 0x2d,
+ 0x8f, 0x48, 0x3f, 0x58, 0x9c, 0x73, 0xf7, 0x39, 0x67, 0xef, 0xb5, 0x1f,
+ 0x67, 0x9f, 0x29, 0x10, 0x42, 0x78, 0x45, 0x7a, 0x64, 0x91, 0x81, 0x22,
+ 0xe8, 0xf6, 0x68, 0x06, 0xcc, 0x0a, 0x91, 0x57, 0x2a, 0xc7, 0xc2, 0x2d,
+ 0xf8, 0x6f, 0x59, 0x01, 0xc1, 0x0f, 0x23, 0xf2, 0xbb, 0x5f, 0xbc, 0xe5,
+ 0xc6, 0x77, 0xaf, 0x90, 0x18, 0x11, 0x22, 0x2d, 0xb1, 0x80, 0x31, 0xc6,
+ 0xe8, 0x72, 0x01, 0x4b, 0x18, 0x5f, 0x61, 0x14, 0x8c, 0xba, 0x1b, 0xe8,
+ 0x66, 0xf4, 0xaa, 0x79, 0x5e, 0xaf, 0xf1, 0x7c, 0x3b, 0xe3, 0x76, 0x9e,
+ 0xff, 0xdd, 0x40, 0xa5, 0x97, 0x1c, 0x4f, 0xce, 0x8a, 0xb4, 0x8e, 0x6d,
+ 0x63, 0x6a, 0x5e, 0x27, 0x48, 0xc7, 0xa0, 0xf7, 0x9b, 0x95, 0xb4, 0xce,
+ 0x41, 0x4e, 0xce, 0xdf, 0x98, 0x55, 0xfb, 0x1d, 0xf4, 0xc8, 0xf1, 0x2f,
+ 0xc6, 0xd8, 0x25, 0x87, 0xc5, 0x51, 0x6c, 0x53, 0x5c, 0x9a, 0x91, 0xfb,
+ 0x78, 0xc4, 0xd0, 0x80, 0x46, 0xac, 0x1c, 0xd7, 0x31, 0x4e, 0x13, 0x1f,
+ 0x2e, 0x63, 0xcc, 0xfb, 0x31, 0x96, 0x85, 0x70, 0xee, 0xd6, 0x4a, 0x9c,
+ 0xf7, 0xd3, 0xb3, 0x90, 0x4b, 0x47, 0x14, 0xa1, 0xf8, 0xbe, 0x48, 0xf0,
+ 0xf7, 0xdd, 0x72, 0x3c, 0xe5, 0x2a, 0x72, 0x81, 0x57, 0xbf, 0x50, 0x7a,
+ 0x42, 0xee, 0xea, 0x40, 0xae, 0x3c, 0x0d, 0x3f, 0x4f, 0xaf, 0x50, 0x76,
+ 0x00, 0xda, 0x42, 0xc0, 0xa4, 0x07, 0xb8, 0x2e, 0x4e, 0x90, 0x69, 0x67,
+ 0x47, 0x36, 0xd7, 0x48, 0x3d, 0x0a, 0x85, 0xd7, 0x2d, 0xf7, 0x5b, 0xa1,
+ 0xf9, 0xce, 0x61, 0xfe, 0x6d, 0xd6, 0xeb, 0xbd, 0x00, 0xf0, 0x46, 0x20,
+ 0xdf, 0xf8, 0x77, 0x76, 0xb6, 0x23, 0x68, 0xb7, 0x2b, 0x1d, 0xc4, 0xfa,
+ 0x31, 0xdd, 0xc9, 0x3e, 0xcf, 0x03, 0xec, 0xc3, 0xba, 0x05, 0x4b, 0xf1,
+ 0xf5, 0xe3, 0x0e, 0x8c, 0x2b, 0x4e, 0x49, 0x39, 0x9f, 0x18, 0x1a, 0x71,
+ 0xe2, 0x23, 0x77, 0x7f, 0x23, 0x4e, 0x23, 0x38, 0x47, 0x54, 0x69, 0xa4,
+ 0x54, 0x3a, 0x0e, 0x14, 0x75, 0x8e, 0xfc, 0x88, 0xe3, 0x4b, 0xe4, 0xbc,
+ 0x5b, 0xb4, 0x7a, 0x74, 0x3a, 0xa7, 0x35, 0xa5, 0xe2, 0x02, 0xdf, 0x3b,
+ 0x7c, 0x04, 0xa5, 0x6d, 0xfd, 0xd2, 0xde, 0x88, 0xd8, 0xee, 0x8e, 0x90,
+ 0x3c, 0xf8, 0xf1, 0x68, 0xfa, 0x97, 0x90, 0xff, 0x66, 0x91, 0x4e, 0x36,
+ 0x75, 0x34, 0x60, 0x5d, 0x71, 0x02, 0x78, 0x2c, 0x91, 0x27, 0x21, 0xde,
+ 0xd1, 0x4b, 0xc3, 0xe5, 0xd7, 0x57, 0x6a, 0x24, 0x97, 0xae, 0x53, 0x71,
+ 0xa7, 0xfc, 0x27, 0xfd, 0x3a, 0x64, 0xc6, 0x99, 0xa8, 0x06, 0xbf, 0xbf,
+ 0x2d, 0x91, 0xf2, 0x06, 0xc9, 0x55, 0x38, 0x27, 0xab, 0x9f, 0x35, 0x6e,
+ 0x07, 0x2c, 0x71, 0xfb, 0x78, 0xf1, 0xb0, 0x8e, 0xf8, 0x59, 0xc7, 0x3c,
+ 0x55, 0x1a, 0x3c, 0x49, 0x5c, 0xe8, 0x4a, 0xd7, 0xd9, 0xfd, 0x74, 0x75,
+ 0x20, 0x42, 0xff, 0xbf, 0xd9, 0x54, 0x40, 0x3c, 0x6f, 0xc6, 0xfc, 0x91,
+ 0xe6, 0xb3, 0xf0, 0xd3, 0x26, 0xe2, 0x43, 0x04, 0x0e, 0x7d, 0x81, 0x55,
+ 0x6d, 0x14, 0xdf, 0xdd, 0x8d, 0x1d, 0x5f, 0x61, 0x9c, 0xf4, 0xc8, 0xf1,
+ 0x6e, 0xbd, 0x7d, 0x14, 0xf2, 0x79, 0x7d, 0xe0, 0x7d, 0x33, 0x9f, 0xb2,
+ 0xc9, 0x43, 0xf9, 0x94, 0xf1, 0xf5, 0xd1, 0x50, 0x1f, 0xa3, 0xef, 0x05,
+ 0xe2, 0xf0, 0x08, 0xbe, 0xef, 0x09, 0x4a, 0x3b, 0xdf, 0x37, 0xf3, 0x2e,
+ 0xe5, 0xc3, 0xfa, 0xcc, 0x00, 0xf2, 0x66, 0xe2, 0x8c, 0x1c, 0x6f, 0x8b,
+ 0x4f, 0x40, 0x3e, 0x9e, 0xea, 0xe7, 0x8d, 0xdd, 0xe0, 0xf1, 0xa6, 0x1b,
+ 0xf2, 0x1c, 0xa6, 0x01, 0x2f, 0xf9, 0xd1, 0x25, 0xf4, 0x66, 0xe0, 0x87,
+ 0xf4, 0xfd, 0x5f, 0x57, 0x86, 0x78, 0xdb, 0x1a, 0xf6, 0x9e, 0x55, 0xfc,
+ 0x30, 0x46, 0x94, 0x5d, 0xc0, 0x47, 0xcd, 0x83, 0xfe, 0x79, 0xf3, 0x80,
+ 0xfd, 0x19, 0x7b, 0x58, 0x1e, 0x00, 0x9b, 0x6b, 0x80, 0xbe, 0x6a, 0x29,
+ 0x9f, 0xff, 0x18, 0xf9, 0xc0, 0x7a, 0xcd, 0xc9, 0x37, 0xcc, 0x66, 0xe3,
+ 0x94, 0xc0, 0x88, 0x4f, 0x5b, 0xbc, 0x72, 0x7e, 0x2c, 0x36, 0xfc, 0xa0,
+ 0xe2, 0x4e, 0x6e, 0xe8, 0x17, 0xbb, 0x79, 0xdf, 0x14, 0xf3, 0xd1, 0xc5,
+ 0x7c, 0x4c, 0x32, 0xee, 0x09, 0x2a, 0x1e, 0x80, 0x87, 0x75, 0x9c, 0xdb,
+ 0x9a, 0x92, 0x7e, 0x5c, 0xeb, 0x50, 0x3f, 0x55, 0x9d, 0x84, 0x9f, 0x86,
+ 0xd8, 0xaf, 0x27, 0xcc, 0x7a, 0xa9, 0xf8, 0x9d, 0xaf, 0x6e, 0xda, 0xf3,
+ 0x29, 0xc7, 0xce, 0xcc, 0x77, 0x55, 0x58, 0x5e, 0x58, 0x0d, 0x34, 0xf9,
+ 0xad, 0xa1, 0x3c, 0x0e, 0x97, 0x8c, 0x2a, 0xfb, 0xa4, 0x7e, 0xb7, 0x55,
+ 0x1e, 0x86, 0x07, 0x0f, 0x12, 0x06, 0x0a, 0x4f, 0xc9, 0x73, 0xca, 0x1d,
+ 0xea, 0x8a, 0x3d, 0x9f, 0x73, 0xf9, 0xdd, 0x13, 0xa2, 0x42, 0xdb, 0x78,
+ 0x79, 0xdc, 0x9e, 0xb7, 0xc8, 0x4f, 0xbf, 0x19, 0xdf, 0xc5, 0xab, 0xd9,
+ 0x0f, 0x8c, 0xd1, 0x35, 0x72, 0xdf, 0x16, 0x3e, 0xa7, 0x9e, 0xcf, 0xd1,
+ 0x2d, 0x75, 0x43, 0xea, 0x59, 0x68, 0xd6, 0x0b, 0x15, 0x1f, 0xd9, 0xba,
+ 0xa1, 0xfc, 0x40, 0xe7, 0xc7, 0x2f, 0x8f, 0xcb, 0xf5, 0x15, 0x0f, 0xa9,
+ 0x23, 0x9a, 0xb9, 0xdf, 0x8f, 0x66, 0x9d, 0x90, 0xdf, 0x83, 0xe2, 0x25,
+ 0x1e, 0xda, 0xeb, 0xe1, 0x1f, 0x46, 0x3d, 0x24, 0x3b, 0x34, 0xfd, 0x2c,
+ 0xd7, 0xbf, 0x5e, 0x79, 0x4e, 0x29, 0xeb, 0x5d, 0xca, 0x7a, 0x1b, 0xd7,
+ 0x73, 0x1d, 0xd7, 0xc9, 0x6d, 0xd6, 0x7a, 0xf7, 0xcf, 0x4c, 0xb6, 0x6e,
+ 0xc9, 0xf1, 0xdf, 0x33, 0x73, 0xef, 0x5f, 0x47, 0x5e, 0xd3, 0x22, 0x82,
+ 0x3e, 0x23, 0x1d, 0x51, 0x7d, 0x41, 0x6e, 0xfd, 0xcb, 0xb5, 0x03, 0xbc,
+ 0xb4, 0xb9, 0x43, 0x24, 0x77, 0xad, 0xc7, 0xde, 0x27, 0xa0, 0x0e, 0x56,
+ 0xba, 0xa0, 0xf7, 0x42, 0xd6, 0xdb, 0xd8, 0xaf, 0x8e, 0xf2, 0x41, 0xbb,
+ 0xd6, 0x63, 0xd5, 0xfb, 0xfa, 0xcc, 0xfc, 0xe7, 0x39, 0xc7, 0x41, 0x0f,
+ 0xdf, 0xaf, 0x49, 0xc4, 0xb1, 0xd6, 0xfe, 0xb5, 0xd2, 0x8b, 0xcf, 0x8f,
+ 0x28, 0x3d, 0x74, 0xf2, 0xd3, 0x78, 0xaf, 0xdc, 0xa7, 0x48, 0x70, 0xd8,
+ 0x88, 0xee, 0x5a, 0xd4, 0xdf, 0xc9, 0x1d, 0xb0, 0xa3, 0xbb, 0x46, 0xea,
+ 0x61, 0x78, 0x25, 0x8d, 0x3c, 0x17, 0x7c, 0x1f, 0x7d, 0x3b, 0xe0, 0xe4,
+ 0xd7, 0x4b, 0x2c, 0x57, 0xcc, 0xf6, 0x15, 0xb0, 0x7d, 0x71, 0x91, 0x5b,
+ 0xe7, 0xb7, 0x55, 0xd2, 0x7d, 0xc0, 0x72, 0x2f, 0xaa, 0xfb, 0xc0, 0x90,
+ 0x93, 0xfb, 0xe4, 0xf1, 0x3e, 0x4e, 0x3c, 0x39, 0xed, 0x33, 0xca, 0x71,
+ 0xd0, 0xc9, 0x72, 0x5e, 0x87, 0x7b, 0x05, 0xa3, 0xe9, 0xa5, 0x74, 0xaf,
+ 0x9c, 0x3c, 0x40, 0xf7, 0x43, 0xc8, 0x8c, 0x53, 0xbb, 0x1d, 0x67, 0x9e,
+ 0x20, 0xef, 0x52, 0x3e, 0x2a, 0x76, 0x86, 0xe7, 0xe3, 0xd7, 0x2b, 0xa7,
+ 0x87, 0xa7, 0x46, 0x95, 0x7f, 0x74, 0xb2, 0x77, 0xbc, 0x57, 0xf5, 0xb1,
+ 0x56, 0xde, 0xdd, 0x16, 0xde, 0x21, 0xff, 0x74, 0xfc, 0xff, 0xf2, 0xed,
+ 0xd4, 0x1f, 0x1c, 0x9d, 0x31, 0xfb, 0x50, 0x9f, 0x53, 0xfd, 0x5f, 0x61,
+ 0xc6, 0xcb, 0x5e, 0xee, 0xef, 0xa6, 0x75, 0xfa, 0x4f, 0x62, 0x32, 0x43,
+ 0x43, 0xbd, 0xec, 0xb4, 0x94, 0x5b, 0x96, 0xd8, 0xcb, 0x76, 0x5d, 0xf4,
+ 0xc0, 0xee, 0xce, 0x1d, 0x18, 0x5f, 0xe6, 0x7a, 0x7d, 0x97, 0xeb, 0xe3,
+ 0x16, 0x0d, 0x38, 0x59, 0x4b, 0x7c, 0x24, 0xf6, 0x9e, 0x53, 0xfb, 0xd3,
+ 0xbe, 0xfa, 0x34, 0xf3, 0xf9, 0xb2, 0x87, 0xed, 0xac, 0x22, 0x3f, 0x26,
+ 0xee, 0x50, 0x3d, 0xf0, 0x8a, 0xa6, 0xc5, 0x12, 0xcb, 0x0c, 0xde, 0x58,
+ 0x9f, 0x17, 0x80, 0xad, 0x7e, 0xa6, 0x21, 0x96, 0xeb, 0x67, 0x4c, 0xfb,
+ 0xaa, 0x78, 0x7d, 0x1b, 0xc6, 0x7e, 0xae, 0x67, 0x83, 0xac, 0xd7, 0xd1,
+ 0x5a, 0x60, 0x38, 0x86, 0x3e, 0x61, 0x9c, 0xee, 0x85, 0x48, 0xa2, 0x77,
+ 0x14, 0xf6, 0x74, 0xad, 0x87, 0xbd, 0xf7, 0x98, 0x07, 0xc6, 0xf0, 0x89,
+ 0x3e, 0xba, 0x77, 0xc2, 0xfd, 0xe8, 0x33, 0xc2, 0xbe, 0x3e, 0xd8, 0xd1,
+ 0x35, 0x8d, 0xf1, 0xbd, 0xe7, 0x80, 0x7f, 0x3d, 0x8f, 0x75, 0xfb, 0x0e,
+ 0x30, 0x3f, 0xeb, 0x9d, 0xd7, 0x75, 0xfe, 0x09, 0xb9, 0xee, 0x5a, 0x79,
+ 0xfe, 0xbb, 0xc3, 0xdc, 0x7f, 0x88, 0x14, 0xf5, 0x3b, 0xef, 0xe8, 0xd3,
+ 0x3c, 0xde, 0xc5, 0xf7, 0xe2, 0x2d, 0xee, 0x17, 0xba, 0x72, 0xfa, 0x85,
+ 0x09, 0xd4, 0xe9, 0xe1, 0xe9, 0x8c, 0x9c, 0x30, 0xea, 0x65, 0xbe, 0x93,
+ 0x7f, 0xf5, 0x44, 0x09, 0xfb, 0xad, 0x78, 0x15, 0xf0, 0xd8, 0x2a, 0xdc,
+ 0xd7, 0x5d, 0xfb, 0x99, 0x9f, 0x46, 0xf2, 0xd3, 0xf2, 0xa9, 0xd1, 0xdc,
+ 0xf5, 0x32, 0x7e, 0x3a, 0x8d, 0xf8, 0x51, 0xe7, 0x40, 0x3e, 0x19, 0x92,
+ 0xf3, 0xf7, 0xcc, 0xba, 0x3f, 0x41, 0x7a, 0x57, 0x0c, 0x4f, 0xd3, 0xfa,
+ 0x72, 0x51, 0x44, 0xf1, 0x57, 0x16, 0x9e, 0x82, 0x1d, 0x89, 0x41, 0xb6,
+ 0xbf, 0x67, 0x2d, 0x70, 0x3f, 0xfb, 0x5f, 0xf9, 0xf5, 0xca, 0x1a, 0x9d,
+ 0xd6, 0x8d, 0xf7, 0xe2, 0x1c, 0x95, 0x3f, 0xb9, 0xfd, 0xb0, 0x8a, 0x87,
+ 0xb2, 0x06, 0x1a, 0x8b, 0xce, 0x7d, 0xf2, 0x9c, 0x90, 0xe1, 0x47, 0x19,
+ 0x47, 0x06, 0x47, 0x7c, 0x5f, 0xdb, 0xe3, 0x44, 0xc6, 0x91, 0x8a, 0x57,
+ 0x6b, 0x7c, 0x59, 0xe3, 0xc7, 0x1e, 0x37, 0x61, 0xba, 0x57, 0x8c, 0x22,
+ 0x90, 0xa6, 0x77, 0x44, 0x62, 0x70, 0xe0, 0xc1, 0xfc, 0x9d, 0x00, 0x7f,
+ 0x09, 0xd6, 0x5b, 0x4f, 0x51, 0x1f, 0xfa, 0x94, 0xe8, 0x67, 0x3f, 0x4e,
+ 0xd4, 0x72, 0xde, 0x57, 0xc1, 0x8f, 0x3d, 0xcf, 0x40, 0x9f, 0x1e, 0xce,
+ 0x9f, 0xdb, 0xdc, 0x5f, 0xc0, 0xff, 0x7e, 0xbd, 0x63, 0x94, 0xfd, 0xcd,
+ 0x71, 0xb8, 0x8b, 0x79, 0xb8, 0x05, 0x1e, 0x74, 0xc5, 0x43, 0xca, 0xe4,
+ 0x41, 0xd5, 0x19, 0xeb, 0x3e, 0x85, 0x46, 0x1c, 0x49, 0x5c, 0xa0, 0x5f,
+ 0xa1, 0x3e, 0x2c, 0x8f, 0xed, 0x36, 0xe4, 0x1a, 0xa4, 0x7d, 0x61, 0xb6,
+ 0x2f, 0x24, 0x76, 0x2e, 0xb7, 0xae, 0x0b, 0xf2, 0xba, 0x80, 0xb1, 0x0e,
+ 0xf3, 0xc8, 0x53, 0x7d, 0x1e, 0x7e, 0x25, 0x8f, 0x6a, 0xdf, 0xdc, 0x7c,
+ 0xb4, 0xf2, 0x49, 0x15, 0x9a, 0xfe, 0x50, 0x87, 0x0c, 0xbf, 0x51, 0xbd,
+ 0xd2, 0xcd, 0xfa, 0x73, 0x97, 0xea, 0x79, 0xe0, 0x64, 0x37, 0xea, 0xc5,
+ 0xc9, 0xee, 0xd3, 0x7c, 0xff, 0x32, 0x2f, 0x2d, 0xf4, 0x6e, 0x30, 0xb8,
+ 0xab, 0xb2, 0xd7, 0x1f, 0xbb, 0x1e, 0x15, 0x16, 0x3d, 0xd4, 0xb9, 0x0f,
+ 0xeb, 0x0f, 0xd0, 0x9f, 0x6e, 0xa0, 0xfe, 0x40, 0x33, 0xfb, 0x6c, 0xfb,
+ 0x3d, 0x72, 0xeb, 0xfe, 0xe3, 0xde, 0x23, 0x5b, 0x1a, 0xac, 0xe7, 0xc5,
+ 0xc4, 0xd8, 0x08, 0xce, 0x69, 0xe1, 0x7b, 0x7b, 0x3b, 0xe7, 0xf7, 0xb5,
+ 0x40, 0x84, 0xce, 0x4d, 0xbe, 0x46, 0xf6, 0x8a, 0x68, 0x10, 0xf6, 0x25,
+ 0x5f, 0xc7, 0xf7, 0x64, 0x08, 0xf3, 0xe5, 0x21, 0xfc, 0x3e, 0xd0, 0xe2,
+ 0xd7, 0x49, 0xbe, 0x3c, 0x04, 0x8c, 0x72, 0x5d, 0x18, 0x33, 0xdf, 0x11,
+ 0xc0, 0x21, 0xdf, 0x7c, 0xef, 0x08, 0xbc, 0xc7, 0xce, 0xfb, 0x50, 0x37,
+ 0x44, 0x0c, 0xfd, 0x73, 0x53, 0x8d, 0x4e, 0xdf, 0x5b, 0x63, 0xb8, 0x9f,
+ 0x51, 0x97, 0xe7, 0xda, 0x55, 0x81, 0x78, 0x2d, 0xcf, 0xbe, 0x37, 0xac,
+ 0xef, 0x12, 0x3d, 0x31, 0x68, 0xf6, 0xfd, 0x76, 0x3d, 0x90, 0x67, 0x72,
+ 0x7f, 0x1a, 0x1a, 0xfd, 0xf5, 0xa3, 0xbc, 0x47, 0x3c, 0xdc, 0xaf, 0xdd,
+ 0x99, 0x45, 0xbc, 0x16, 0x89, 0x0b, 0x23, 0xe0, 0x61, 0x6c, 0xc4, 0x29,
+ 0x8f, 0xa5, 0x1e, 0xea, 0x1c, 0xd8, 0xa5, 0xec, 0xcc, 0x9e, 0x0b, 0xbd,
+ 0x76, 0xb0, 0xfe, 0xbf, 0xd2, 0xef, 0x17, 0x51, 0xb6, 0x57, 0xee, 0x8b,
+ 0xf9, 0x8d, 0xf4, 0x6e, 0xca, 0x13, 0x69, 0x73, 0x6c, 0x7f, 0xcf, 0xb4,
+ 0x90, 0x5e, 0x85, 0x7c, 0xaf, 0x47, 0x2d, 0xfd, 0x07, 0xe4, 0x8b, 0xeb,
+ 0x81, 0xc7, 0xea, 0x95, 0xdf, 0x94, 0x7f, 0x95, 0x3f, 0xe1, 0xf7, 0xe8,
+ 0x4a, 0x12, 0x6b, 0x4c, 0xae, 0xa4, 0x84, 0xaf, 0x4f, 0x4e, 0xa9, 0x7b,
+ 0x1e, 0xeb, 0xb7, 0xc4, 0xa5, 0xfc, 0x07, 0xe2, 0xfb, 0x38, 0x2e, 0xd6,
+ 0x9f, 0x19, 0xb3, 0xfd, 0xbd, 0xe0, 0x3f, 0xeb, 0x3b, 0xc1, 0x23, 0xce,
+ 0xe7, 0xf1, 0x74, 0x83, 0xea, 0x7b, 0xe7, 0x7b, 0xef, 0x48, 0x3b, 0x3e,
+ 0xba, 0x9f, 0xdb, 0x47, 0x67, 0xfb, 0x60, 0x65, 0xaf, 0x5c, 0x57, 0xcf,
+ 0x71, 0xac, 0x89, 0xa6, 0x0d, 0xf8, 0x7d, 0x23, 0xec, 0x47, 0xde, 0x84,
+ 0xfd, 0x4e, 0xef, 0x52, 0x23, 0x8e, 0xf2, 0xa9, 0x60, 0x2c, 0x2c, 0xcc,
+ 0x27, 0xfb, 0x8e, 0x5c, 0xbc, 0x44, 0x62, 0x9f, 0x0d, 0x06, 0x31, 0x5f,
+ 0xd2, 0x84, 0x63, 0xbc, 0x14, 0xf7, 0x1e, 0x71, 0x08, 0x79, 0xf1, 0xe9,
+ 0x31, 0xe0, 0x27, 0xe2, 0x55, 0xec, 0x53, 0x78, 0x90, 0xee, 0x53, 0xad,
+ 0x04, 0x34, 0x67, 0x06, 0x39, 0xde, 0x4b, 0xdd, 0xf4, 0xfb, 0xe2, 0xac,
+ 0x08, 0x49, 0xf4, 0x99, 0xf9, 0x8b, 0xb8, 0xf6, 0x5a, 0xfc, 0xff, 0xa8,
+ 0x71, 0x4e, 0xf5, 0xc9, 0x88, 0x63, 0x6c, 0xc3, 0xf1, 0xae, 0xe5, 0xc6,
+ 0xbb, 0xe2, 0xa9, 0xd4, 0xed, 0x18, 0xdf, 0xab, 0xe7, 0xc6, 0xb7, 0xd2,
+ 0x4f, 0xf2, 0x7d, 0xd7, 0xbc, 0x3f, 0xe7, 0xee, 0x8f, 0xf7, 0xd3, 0x85,
+ 0x27, 0x16, 0xdf, 0xc0, 0x8d, 0xd5, 0xf2, 0xfc, 0x92, 0x39, 0x7d, 0x72,
+ 0x6e, 0xfe, 0xa1, 0xde, 0xbd, 0x61, 0xc4, 0xc3, 0x7f, 0x69, 0x4a, 0x77,
+ 0x8f, 0xc8, 0x15, 0x00, 0x00, 0x00 };
static u8 bnx2_TPAT_b09FwText[] = {
0xbd, 0x58, 0x5d, 0x6c, 0x1c, 0xd5, 0x15, 0x3e, 0x73, 0x67, 0xd6, 0x3b,
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6e91b4b7aabb..50a40e433154 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1425,13 +1425,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
res = netdev_set_master(slave_dev, bond_dev);
if (res) {
dprintk("Error %d calling netdev_set_master\n", res);
- goto err_close;
+ goto err_restore_mac;
}
/* open the slave since the application closed it */
res = dev_open(slave_dev);
if (res) {
dprintk("Openning slave %s failed\n", slave_dev->name);
- goto err_restore_mac;
+ goto err_unset_master;
}
new_slave->dev = slave_dev;
@@ -1444,7 +1444,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
*/
res = bond_alb_init_slave(bond, new_slave);
if (res) {
- goto err_unset_master;
+ goto err_close;
}
}
@@ -1619,7 +1619,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
res = bond_create_slave_symlinks(bond_dev, slave_dev);
if (res)
- goto err_unset_master;
+ goto err_close;
printk(KERN_INFO DRV_NAME
": %s: enslaving %s as a%s interface with a%s link.\n",
@@ -1631,12 +1631,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
return 0;
/* Undo stages on error */
-err_unset_master:
- netdev_set_master(slave_dev, NULL);
-
err_close:
dev_close(slave_dev);
+err_unset_master:
+ netdev_set_master(slave_dev, NULL);
+
err_restore_mac:
if (!bond->params.fail_over_mac) {
memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
@@ -3282,17 +3282,14 @@ static int bond_create_proc_entry(struct bonding *bond)
struct net_device *bond_dev = bond->dev;
if (bond_proc_dir) {
- bond->proc_entry = create_proc_entry(bond_dev->name,
- S_IRUGO,
- bond_proc_dir);
+ bond->proc_entry = proc_create_data(bond_dev->name,
+ S_IRUGO, bond_proc_dir,
+ &bond_info_fops, bond);
if (bond->proc_entry == NULL) {
printk(KERN_WARNING DRV_NAME
": Warning: Cannot create /proc/net/%s/%s\n",
DRV_NAME, bond_dev->name);
} else {
- bond->proc_entry->data = bond;
- bond->proc_entry->proc_fops = &bond_info_fops;
- bond->proc_entry->owner = THIS_MODULE;
memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ);
}
}
@@ -4939,7 +4936,9 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
if (res < 0) {
rtnl_lock();
down_write(&bonding_rwsem);
- goto out_bond;
+ bond_deinit(bond_dev);
+ unregister_netdevice(bond_dev);
+ goto out_rtnl;
}
return 0;
@@ -4993,9 +4992,10 @@ err:
destroy_workqueue(bond->wq);
}
+ bond_destroy_sysfs();
+
rtnl_lock();
bond_free_all();
- bond_destroy_sysfs();
rtnl_unlock();
out:
return res;
@@ -5007,9 +5007,10 @@ static void __exit bonding_exit(void)
unregister_netdevice_notifier(&bond_netdev_notifier);
unregister_inetaddr_notifier(&bond_inetaddr_notifier);
+ bond_destroy_sysfs();
+
rtnl_lock();
bond_free_all();
- bond_destroy_sysfs();
rtnl_unlock();
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 979c2d05ff9c..68c41a00d93d 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -146,29 +146,29 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
": Unable remove bond %s due to open references.\n",
ifname);
res = -EPERM;
- goto out;
+ goto out_unlock;
}
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
bond_destroy(bond);
- up_write(&bonding_rwsem);
- rtnl_unlock();
- goto out;
+ goto out_unlock;
}
printk(KERN_ERR DRV_NAME
": unable to delete non-existent bond %s\n", ifname);
res = -ENODEV;
- up_write(&bonding_rwsem);
- rtnl_unlock();
- goto out;
+ goto out_unlock;
}
err_no_cmd:
printk(KERN_ERR DRV_NAME
": no command found in bonding_masters. Use +ifname or -ifname.\n");
- res = -EPERM;
+ return -EPERM;
+
+out_unlock:
+ up_write(&bonding_rwsem);
+ rtnl_unlock();
/* Always return either count or an error. If you return 0, you'll
* get called forever, which is bad.
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 4fdb13f8447b..acebe431d068 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -71,6 +71,7 @@ enum { /* adapter flags */
USING_MSIX = (1 << 2),
QUEUES_BOUND = (1 << 3),
TP_PARITY_INIT = (1 << 4),
+ NAPI_INIT = (1 << 5),
};
struct fl_pg_chunk {
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 91ee7277b813..579bee42a5cb 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -698,6 +698,7 @@ 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);
+int t3_replay_prep_adapter(struct adapter *adapter);
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);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 05e5f59e87fa..3a3127216791 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -421,6 +421,13 @@ static void init_napi(struct adapter *adap)
netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
64);
}
+
+ /*
+ * netif_napi_add() can be called only once per napi_struct because it
+ * adds each new napi_struct to a list. Be careful not to call it a
+ * second time, e.g., during EEH recovery, by making a note of it.
+ */
+ adap->flags |= NAPI_INIT;
}
/*
@@ -896,7 +903,8 @@ static int cxgb_up(struct adapter *adap)
goto out;
setup_rss(adap);
- init_napi(adap);
+ if (!(adap->flags & NAPI_INIT))
+ init_napi(adap);
adap->flags |= FULL_INIT_DONE;
}
@@ -999,7 +1007,7 @@ static int offload_open(struct net_device *dev)
return 0;
if (!adap_up && (err = cxgb_up(adapter)) < 0)
- return err;
+ goto out;
t3_tp_set_offload_mode(adapter, 1);
tdev->lldev = adapter->port[0];
@@ -1061,10 +1069,8 @@ static int cxgb_open(struct net_device *dev)
int other_ports = adapter->open_device_map & PORT_MASK;
int err;
- if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
- quiesce_rx(adapter);
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
return err;
- }
set_bit(pi->port_id, &adapter->open_device_map);
if (is_offload(adapter) && !ofld_disable) {
@@ -1894,11 +1900,11 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
u8 *fw_data;
struct ch_mem_range t;
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_SYS_RAWIO))
return -EPERM;
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
-
+ /* Check t.len sanity ? */
fw_data = kmalloc(t.len, GFP_KERNEL);
if (!fw_data)
return -ENOMEM;
@@ -2424,14 +2430,11 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
offload_close(&adapter->tdev);
- /* Free sge resources */
- t3_free_sge_resources(adapter);
-
adapter->flags &= ~FULL_INIT_DONE;
pci_disable_device(pdev);
- /* Request a slot slot reset. */
+ /* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
@@ -2448,13 +2451,20 @@ static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev,
"Cannot re-enable PCI device after reset.\n");
- return PCI_ERS_RESULT_DISCONNECT;
+ goto err;
}
pci_set_master(pdev);
+ pci_restore_state(pdev);
- t3_prep_adapter(adapter, adapter->params.info, 1);
+ /* Free sge resources */
+ t3_free_sge_resources(adapter);
+
+ if (t3_replay_prep_adapter(adapter))
+ goto err;
return PCI_ERS_RESULT_RECOVERED;
+err:
+ return PCI_ERS_RESULT_DISCONNECT;
}
/**
@@ -2483,13 +2493,6 @@ static void t3_io_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
}
}
-
- if (is_offload(adapter)) {
- __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
- if (offload_open(adapter->port[0]))
- printk(KERN_WARNING
- "Could not bring back offload capabilities\n");
- }
}
static struct pci_error_handlers t3_err_handler = {
@@ -2608,6 +2611,7 @@ static int __devinit init_one(struct pci_dev *pdev,
}
pci_set_master(pdev);
+ pci_save_state(pdev);
mmio_start = pci_resource_start(pdev, 0);
mmio_len = pci_resource_len(pdev, 0);
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 02dbbb300929..567178879345 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -444,6 +444,14 @@
#define A_PCIE_CFG 0x88
+#define S_ENABLELINKDWNDRST 21
+#define V_ENABLELINKDWNDRST(x) ((x) << S_ENABLELINKDWNDRST)
+#define F_ENABLELINKDWNDRST V_ENABLELINKDWNDRST(1U)
+
+#define S_ENABLELINKDOWNRST 20
+#define V_ENABLELINKDOWNRST(x) ((x) << S_ENABLELINKDOWNRST)
+#define F_ENABLELINKDOWNRST V_ENABLELINKDOWNRST(1U)
+
#define S_PCIE_CLIDECEN 16
#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 98a6bbd11d4c..796eb305cdc3 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -539,6 +539,31 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
}
/**
+ * t3_reset_qset - reset a sge qset
+ * @q: the queue set
+ *
+ * Reset the qset structure.
+ * the NAPI structure is preserved in the event of
+ * the qset's reincarnation, for example during EEH recovery.
+ */
+static void t3_reset_qset(struct sge_qset *q)
+{
+ if (q->adap &&
+ !(q->adap->flags & NAPI_INIT)) {
+ memset(q, 0, sizeof(*q));
+ return;
+ }
+
+ q->adap = NULL;
+ memset(&q->rspq, 0, sizeof(q->rspq));
+ memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET);
+ memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
+ q->txq_stopped = 0;
+ memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer));
+}
+
+
+/**
* free_qset - free the resources of an SGE queue set
* @adapter: the adapter owning the queue set
* @q: the queue set
@@ -594,7 +619,7 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
q->rspq.desc, q->rspq.phys_addr);
}
- memset(q, 0, sizeof(*q));
+ t3_reset_qset(q);
}
/**
@@ -1365,7 +1390,7 @@ static void restart_ctrlq(unsigned long data)
*/
int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
{
- int ret;
+ int ret;
local_bh_disable();
ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
local_bh_enable();
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index a99496a431c4..d405a932c73a 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -3264,6 +3264,7 @@ static void config_pcie(struct adapter *adap)
t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
t3_set_reg_field(adap, A_PCIE_CFG, 0,
+ F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
}
@@ -3655,3 +3656,30 @@ void t3_led_ready(struct adapter *adapter)
t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
F_GPIO0_OUT_VAL);
}
+
+int t3_replay_prep_adapter(struct adapter *adapter)
+{
+ const struct adapter_info *ai = adapter->params.info;
+ unsigned int i, j = 0;
+ int ret;
+
+ early_hw_init(adapter, ai);
+ ret = init_parity(adapter);
+ if (ret)
+ return ret;
+
+ for_each_port(adapter, i) {
+ struct port_info *p = adap2pinfo(adapter, i);
+ while (!adapter->params.vpd.port_type[j])
+ ++j;
+
+ p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+ ai->mdio_ops);
+
+ p->phy.ops->power_down(&p->phy, 1);
+ ++j;
+ }
+
+return 0;
+}
+
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 229303ff6a39..a0177fc55e28 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -38,7 +38,7 @@
#define DRV_VERSION "1.0-ko"
/* Firmware version */
-#define FW_VERSION_MAJOR 5
+#define FW_VERSION_MAJOR 6
#define FW_VERSION_MINOR 0
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index e6fe2614ea6d..d45bcd2660af 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -117,6 +117,9 @@ typedef struct board_info {
struct mutex addr_lock; /* phy and eeprom access lock */
+ struct delayed_work phy_poll;
+ struct net_device *ndev;
+
spinlock_t lock;
struct mii_if_info mii;
@@ -297,6 +300,10 @@ static void dm9000_set_io(struct board_info *db, int byte_width)
}
}
+static void dm9000_schedule_poll(board_info_t *db)
+{
+ schedule_delayed_work(&db->phy_poll, HZ * 2);
+}
/* Our watchdog timed out. Called by the networking layer */
static void dm9000_timeout(struct net_device *dev)
@@ -465,6 +472,17 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.set_eeprom = dm9000_set_eeprom,
};
+static void
+dm9000_poll_work(struct work_struct *w)
+{
+ struct delayed_work *dw = container_of(w, struct delayed_work, work);
+ board_info_t *db = container_of(dw, board_info_t, phy_poll);
+
+ mii_check_media(&db->mii, netif_msg_link(db), 0);
+
+ if (netif_running(db->ndev))
+ dm9000_schedule_poll(db);
+}
/* dm9000_release_board
*
@@ -503,7 +521,7 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db)
/*
* Search DM9000 board, allocate space and register it
*/
-static int
+static int __devinit
dm9000_probe(struct platform_device *pdev)
{
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
@@ -525,17 +543,21 @@ dm9000_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, &pdev->dev);
- dev_dbg(&pdev->dev, "dm9000_probe()");
+ dev_dbg(&pdev->dev, "dm9000_probe()\n");
/* setup board info structure */
db = (struct board_info *) ndev->priv;
memset(db, 0, sizeof (*db));
db->dev = &pdev->dev;
+ db->ndev = ndev;
spin_lock_init(&db->lock);
mutex_init(&db->addr_lock);
+ INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
+
+
if (pdev->num_resources < 2) {
ret = -ENODEV;
goto out;
@@ -761,6 +783,8 @@ dm9000_open(struct net_device *dev)
mii_check_media(&db->mii, netif_msg_link(db), 1);
netif_start_queue(dev);
+
+ dm9000_schedule_poll(db);
return 0;
}
@@ -879,6 +903,8 @@ dm9000_stop(struct net_device *ndev)
if (netif_msg_ifdown(db))
dev_dbg(db->dev, "shutting down %s\n", ndev->name);
+ cancel_delayed_work(&db->phy_poll);
+
netif_stop_queue(ndev);
netif_carrier_off(ndev);
@@ -1288,6 +1314,8 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
spin_unlock_irqrestore(&db->lock,flags);
mutex_unlock(&db->addr_lock);
+
+ dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
return ret;
}
@@ -1301,6 +1329,7 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value)
unsigned long flags;
unsigned long reg_save;
+ dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
mutex_lock(&db->addr_lock);
spin_lock_irqsave(&db->lock,flags);
@@ -1372,7 +1401,7 @@ dm9000_drv_resume(struct platform_device *dev)
return 0;
}
-static int
+static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
@@ -1393,7 +1422,7 @@ static struct platform_driver dm9000_driver = {
.owner = THIS_MODULE,
},
.probe = dm9000_probe,
- .remove = dm9000_drv_remove,
+ .remove = __devexit_p(dm9000_drv_remove),
.suspend = dm9000_drv_suspend,
.resume = dm9000_drv_resume,
};
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 2d139ec79777..f3cba5e24ec5 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1802,7 +1802,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
* it is protected by the before last buffer's el bit being set */
if (rx->prev->skb) {
struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
- put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link);
+ put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
}
return 0;
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 2a53875cddbf..f823b8ba5785 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -648,6 +648,8 @@
#define IFE_E_PHY_ID 0x02A80330
#define IFE_PLUS_E_PHY_ID 0x02A80320
#define IFE_C_E_PHY_ID 0x02A80310
+#define BME1000_E_PHY_ID 0x01410CB0
+#define BME1000_E_PHY_ID_R2 0x01410CB1
/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
@@ -701,6 +703,14 @@
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+/* BME1000 PHY Specific Control Register */
+#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */
+
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+ ((reg) & MAX_PHY_REG_ADDRESS))
+
/*
* Bits...
* 15-5: page
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 38bfd0d261fe..d3bc6f8101fa 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -127,7 +127,7 @@ struct e1000_buffer {
/* arrays of page information for packet split */
struct e1000_ps_page *ps_pages;
};
-
+ struct page *page;
};
struct e1000_ring {
@@ -304,6 +304,7 @@ struct e1000_info {
#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5)
#define FLAG_HAS_SWSM_ON_LOAD (1 << 6)
#define FLAG_HAS_JUMBO_FRAMES (1 << 7)
+#define FLAG_IS_ICH (1 << 9)
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
#define FLAG_IS_QUAD_PORT_A (1 << 12)
#define FLAG_IS_QUAD_PORT (1 << 13)
@@ -386,6 +387,7 @@ extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
bool state);
extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
@@ -443,6 +445,9 @@ extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
+extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index ce045acce63e..a14561f40db0 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -494,8 +494,12 @@ static int e1000_get_eeprom(struct net_device *netdev,
for (i = 0; i < last_word - first_word + 1; i++) {
ret_val = e1000_read_nvm(hw, first_word + i, 1,
&eeprom_buff[i]);
- if (ret_val)
+ if (ret_val) {
+ /* a read error occurred, throw away the
+ * result */
+ memset(eeprom_buff, 0xff, sizeof(eeprom_buff));
break;
+ }
}
}
@@ -803,8 +807,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
/* restore previous status */
ew32(STATUS, before);
- if ((mac->type != e1000_ich8lan) &&
- (mac->type != e1000_ich9lan)) {
+ if (!(adapter->flags & FLAG_IS_ICH)) {
REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF);
@@ -824,15 +827,13 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000);
- before = (((mac->type == e1000_ich8lan) ||
- (mac->type == e1000_ich9lan)) ? 0x06C3B33E : 0x06DFB3FE);
+ before = ((adapter->flags & FLAG_IS_ICH) ? 0x06C3B33E : 0x06DFB3FE);
REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB);
REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000);
REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF);
REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
- if ((mac->type != e1000_ich8lan) &&
- (mac->type != e1000_ich9lan))
+ if (!(adapter->flags & FLAG_IS_ICH))
REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
@@ -911,9 +912,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
/* Test each interrupt */
for (i = 0; i < 10; i++) {
-
- if (((adapter->hw.mac.type == e1000_ich8lan) ||
- (adapter->hw.mac.type == e1000_ich9lan)) && i == 8)
+ if ((adapter->flags & FLAG_IS_ICH) && (i == 8))
continue;
/* Interrupt to test */
@@ -1184,6 +1183,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 ctrl_reg = 0;
u32 stat_reg = 0;
+ u16 phy_reg = 0;
hw->mac.autoneg = 0;
@@ -1211,6 +1211,28 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
E1000_CTRL_SPD_100 |/* Force Speed to 100 */
E1000_CTRL_FD); /* Force Duplex to FULL */
break;
+ case e1000_phy_bm:
+ /* Set Default MAC Interface speed to 1GB */
+ e1e_rphy(hw, PHY_REG(2, 21), &phy_reg);
+ phy_reg &= ~0x0007;
+ phy_reg |= 0x006;
+ e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
+ /* Assert SW reset for above settings to take effect */
+ e1000e_commit_phy(hw);
+ mdelay(1);
+ /* Force Full Duplex */
+ e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
+ e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x000C);
+ /* Set Link Up (in force link) */
+ e1e_rphy(hw, PHY_REG(776, 16), &phy_reg);
+ e1e_wphy(hw, PHY_REG(776, 16), phy_reg | 0x0040);
+ /* Force Link */
+ e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
+ e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x0040);
+ /* Set Early Link Enable */
+ e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
+ e1e_wphy(hw, PHY_REG(769, 20), phy_reg | 0x0400);
+ /* fall through */
default:
/* force 1000, set loopback */
e1e_wphy(hw, PHY_CONTROL, 0x4140);
@@ -1224,8 +1246,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
E1000_CTRL_FD); /* Force Duplex to FULL */
- if ((adapter->hw.mac.type == e1000_ich8lan) ||
- (adapter->hw.mac.type == e1000_ich9lan))
+ if (adapter->flags & FLAG_IS_ICH)
ctrl_reg |= E1000_CTRL_SLU; /* Set Link Up */
}
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index a930e6d9cf02..74f263acb172 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -216,6 +216,21 @@ enum e1e_registers {
#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
+#define IGP_PAGE_SHIFT 5
+#define PHY_REG_MASK 0x1F
+
+#define BM_WUC_PAGE 800
+#define BM_WUC_ADDRESS_OPCODE 0x11
+#define BM_WUC_DATA_OPCODE 0x12
+#define BM_WUC_ENABLE_PAGE 769
+#define BM_WUC_ENABLE_REG 17
+#define BM_WUC_ENABLE_BIT (1 << 2)
+#define BM_WUC_HOST_WU_BIT (1 << 4)
+
+#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
#define IGP01E1000_PHY_POLARITY_MASK 0x0078
@@ -331,10 +346,16 @@ enum e1e_registers {
#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
#define E1000_DEV_ID_ICH8_IGP_M 0x104D
#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
+#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5
+#define E1000_DEV_ID_ICH9_IGP_M 0x10BF
+#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB
#define E1000_DEV_ID_ICH9_IGP_C 0x294C
#define E1000_DEV_ID_ICH9_IFE 0x10C0
#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3
#define E1000_DEV_ID_ICH9_IFE_G 0x10C2
+#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC
+#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD
+#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
#define E1000_FUNC_1 1
@@ -378,6 +399,7 @@ enum e1000_phy_type {
e1000_phy_gg82563,
e1000_phy_igp_3,
e1000_phy_ife,
+ e1000_phy_bm,
};
enum e1000_bus_width {
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 768485dbb2c6..9e38452a738c 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -38,6 +38,12 @@
* 82566DM Gigabit Network Connection
* 82566MC Gigabit Network Connection
* 82566MM Gigabit Network Connection
+ * 82567LM Gigabit Network Connection
+ * 82567LF Gigabit Network Connection
+ * 82567LM-2 Gigabit Network Connection
+ * 82567LF-2 Gigabit Network Connection
+ * 82567V-2 Gigabit Network Connection
+ * 82562GT-3 10/100 Network Connection
*/
#include <linux/netdevice.h>
@@ -198,6 +204,19 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
phy->addr = 1;
phy->reset_delay_us = 100;
+ /*
+ * We may need to do this twice - once for IGP and if that fails,
+ * we'll set BM func pointers and try again
+ */
+ ret_val = e1000e_determine_phy_address(hw);
+ if (ret_val) {
+ hw->phy.ops.write_phy_reg = e1000e_write_phy_reg_bm;
+ hw->phy.ops.read_phy_reg = e1000e_read_phy_reg_bm;
+ ret_val = e1000e_determine_phy_address(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
phy->id = 0;
while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
(i++ < 100)) {
@@ -219,6 +238,13 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
phy->type = e1000_phy_ife;
phy->autoneg_mask = E1000_ALL_NOT_GIG;
break;
+ case BME1000_E_PHY_ID:
+ phy->type = e1000_phy_bm;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ hw->phy.ops.read_phy_reg = e1000e_read_phy_reg_bm;
+ hw->phy.ops.write_phy_reg = e1000e_write_phy_reg_bm;
+ hw->phy.ops.commit_phy = e1000e_phy_sw_reset;
+ break;
default:
return -E1000_ERR_PHY;
break;
@@ -664,6 +690,7 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
return e1000_get_phy_info_ife_ich8lan(hw);
break;
case e1000_phy_igp_3:
+ case e1000_phy_bm:
return e1000e_get_phy_info_igp(hw);
break;
default:
@@ -728,7 +755,7 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
s32 ret_val = 0;
u16 data;
- if (phy->type != e1000_phy_igp_3)
+ if (phy->type == e1000_phy_ife)
return ret_val;
phy_ctrl = er32(PHY_CTRL);
@@ -1918,8 +1945,35 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
ret_val = e1000e_copper_link_setup_igp(hw);
if (ret_val)
return ret_val;
+ } else if (hw->phy.type == e1000_phy_bm) {
+ ret_val = e1000e_copper_link_setup_m88(hw);
+ if (ret_val)
+ return ret_val;
}
+ if (hw->phy.type == e1000_phy_ife) {
+ ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+ switch (hw->phy.mdix) {
+ case 1:
+ reg_data &= ~IFE_PMC_FORCE_MDIX;
+ break;
+ case 2:
+ reg_data |= IFE_PMC_FORCE_MDIX;
+ break;
+ case 0:
+ default:
+ reg_data |= IFE_PMC_AUTO_MDIX;
+ break;
+ }
+ ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data);
+ if (ret_val)
+ return ret_val;
+ }
return e1000e_setup_copper_link(hw);
}
@@ -2127,6 +2181,31 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
}
/**
+ * e1000e_disable_gig_wol_ich8lan - disable gig during WoL
+ * @hw: pointer to the HW structure
+ *
+ * During S0 to Sx transition, it is possible the link remains at gig
+ * instead of negotiating to a lower speed. Before going to Sx, set
+ * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ * to a lower speed.
+ *
+ * Should only be called for ICH9 devices.
+ **/
+void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+ u32 phy_ctrl;
+
+ if (hw->mac.type == e1000_ich9lan) {
+ phy_ctrl = er32(PHY_CTRL);
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
+ E1000_PHY_CTRL_GBE_DISABLE;
+ ew32(PHY_CTRL, phy_ctrl);
+ }
+
+ return;
+}
+
+/**
* e1000_cleanup_led_ich8lan - Restore the default LED operation
* @hw: pointer to the HW structure
*
@@ -2247,6 +2326,7 @@ static struct e1000_nvm_operations ich8_nvm_ops = {
struct e1000_info e1000_ich8_info = {
.mac = e1000_ich8lan,
.flags = FLAG_HAS_WOL
+ | FLAG_IS_ICH
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
@@ -2262,6 +2342,7 @@ struct e1000_info e1000_ich8_info = {
struct e1000_info e1000_ich9_info = {
.mac = e1000_ich9lan,
.flags = FLAG_HAS_JUMBO_FRAMES
+ | FLAG_IS_ICH
| FLAG_HAS_WOL
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 8991ab8911e2..8cbb40f3a506 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -43,10 +43,11 @@
#include <linux/if_vlan.h>
#include <linux/cpu.h>
#include <linux/smp.h>
+#include <linux/pm_qos_params.h>
#include "e1000.h"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.3.3.3-k2"
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -341,6 +342,89 @@ no_buffers:
}
/**
+ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers
+ * @adapter: address of board private structure
+ * @rx_ring: pointer to receive ring structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+
+static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = 256 -
+ 16 /* for skb_reserve */ -
+ NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ skb = buffer_info->skb;
+ if (skb) {
+ skb_trim(skb, 0);
+ goto check_page;
+ }
+
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+ 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);
+
+ buffer_info->skb = skb;
+check_page:
+ /* allocate a new page if necessary */
+ if (!buffer_info->page) {
+ buffer_info->page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!buffer_info->page)) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+ }
+
+ if (!buffer_info->dma)
+ buffer_info->dma = pci_map_page(pdev,
+ buffer_info->page, 0,
+ PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ if (unlikely(++i == rx_ring->count))
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (likely(rx_ring->next_to_use != i)) {
+ rx_ring->next_to_use = i;
+ if (unlikely(i-- == 0))
+ i = (rx_ring->count - 1);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ }
+}
+
+/**
* e1000_clean_rx_irq - Send received data up the network stack; legacy
* @adapter: board private structure
*
@@ -783,6 +867,186 @@ next_desc:
}
/**
+ * e1000_consume_page - helper function
+ **/
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+ u16 length)
+{
+ bi->page = NULL;
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+}
+
+/**
+ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ int *work_done, int work_to_do)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_rx_desc *rx_desc, *next_rxd;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ u32 length;
+ unsigned int i;
+ int cleaned_count = 0;
+ bool cleaned = false;
+ unsigned int total_rx_bytes=0, total_rx_packets=0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (rx_desc->status & E1000_RXD_STAT_DD) {
+ struct sk_buff *skb;
+ u8 status;
+
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ status = rx_desc->status;
+ skb = buffer_info->skb;
+ buffer_info->skb = NULL;
+
+ ++i;
+ if (i == rx_ring->count)
+ i = 0;
+ next_rxd = E1000_RX_DESC(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = true;
+ cleaned_count++;
+ pci_unmap_page(pdev, buffer_info->dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ length = le16_to_cpu(rx_desc->length);
+
+ /* errors is only valid for DD + EOP descriptors */
+ if (unlikely((status & E1000_RXD_STAT_EOP) &&
+ (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
+ /* recycle both page and skb */
+ buffer_info->skb = skb;
+ /* an error means any chain goes out the window
+ * too */
+ if (rx_ring->rx_skb_top)
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ goto next_desc;
+ }
+
+#define rxtop rx_ring->rx_skb_top
+ if (!(status & E1000_RXD_STAT_EOP)) {
+ /* this descriptor is only the beginning (or middle) */
+ if (!rxtop) {
+ /* this is the beginning of a chain */
+ rxtop = skb;
+ skb_fill_page_desc(rxtop, 0, buffer_info->page,
+ 0, length);
+ } else {
+ /* this is the middle of a chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the skb, only consumed the page */
+ buffer_info->skb = skb;
+ }
+ e1000_consume_page(buffer_info, rxtop, length);
+ goto next_desc;
+ } else {
+ if (rxtop) {
+ /* end of the chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the current skb, we only consumed the
+ * page */
+ buffer_info->skb = skb;
+ skb = rxtop;
+ rxtop = NULL;
+ e1000_consume_page(buffer_info, skb, length);
+ } else {
+ /* no chain, got EOP, this buf is the packet
+ * copybreak to save the put_page/alloc_page */
+ if (length <= copybreak &&
+ skb_tailroom(skb) >= length) {
+ u8 *vaddr;
+ vaddr = kmap_atomic(buffer_info->page,
+ KM_SKB_DATA_SOFTIRQ);
+ memcpy(skb_tail_pointer(skb), vaddr,
+ length);
+ kunmap_atomic(vaddr,
+ KM_SKB_DATA_SOFTIRQ);
+ /* re-use the page, so don't erase
+ * buffer_info->page */
+ skb_put(skb, length);
+ } else {
+ skb_fill_page_desc(skb, 0,
+ buffer_info->page, 0,
+ length);
+ e1000_consume_page(buffer_info, skb,
+ length);
+ }
+ }
+ }
+
+ /* Receive Checksum Offload XXX recompute due to CRC strip? */
+ e1000_rx_checksum(adapter,
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ /* eth type trans needs skb->data to point to something */
+ if (!pskb_may_pull(skb, ETH_HLEN)) {
+ ndev_err(netdev, "pskb_may_pull failed.\n");
+ dev_kfree_skb(skb);
+ goto next_desc;
+ }
+
+ e1000_receive_skb(adapter, netdev, skb, status,
+ rx_desc->special);
+
+next_desc:
+ rx_desc->status = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
+ adapter->alloc_rx_buf(adapter, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ buffer_info = next_buffer;
+ }
+ rx_ring->next_to_clean = i;
+
+ cleaned_count = e1000_desc_unused(rx_ring);
+ if (cleaned_count)
+ adapter->alloc_rx_buf(adapter, cleaned_count);
+
+ adapter->total_rx_bytes += total_rx_bytes;
+ adapter->total_rx_packets += total_rx_packets;
+ adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
+ return cleaned;
+}
+
+/**
* e1000_clean_rx_ring - Free Rx Buffers per Queue
* @adapter: board private structure
**/
@@ -802,6 +1066,10 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
pci_unmap_single(pdev, buffer_info->dma,
adapter->rx_buffer_len,
PCI_DMA_FROMDEVICE);
+ else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq)
+ pci_unmap_page(pdev, buffer_info->dma,
+ PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
else if (adapter->clean_rx == e1000_clean_rx_irq_ps)
pci_unmap_single(pdev, buffer_info->dma,
adapter->rx_ps_bsize0,
@@ -809,6 +1077,11 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
buffer_info->dma = 0;
}
+ if (buffer_info->page) {
+ put_page(buffer_info->page);
+ buffer_info->page = NULL;
+ }
+
if (buffer_info->skb) {
dev_kfree_skb(buffer_info->skb);
buffer_info->skb = NULL;
@@ -1755,10 +2028,12 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
* a lot of memory, since we allocate 3 pages at all times
* per packet.
*/
- adapter->rx_ps_pages = 0;
pages = PAGE_USE_COUNT(adapter->netdev->mtu);
- if ((pages <= 3) && (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
+ if (!(adapter->flags & FLAG_IS_ICH) && (pages <= 3) &&
+ (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
adapter->rx_ps_pages = pages;
+ else
+ adapter->rx_ps_pages = 0;
if (adapter->rx_ps_pages) {
/* Configure extra packet-split registers */
@@ -1819,9 +2094,12 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
sizeof(union e1000_rx_desc_packet_split);
adapter->clean_rx = e1000_clean_rx_irq_ps;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
+ } else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) {
+ rdlen = rx_ring->count * sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_jumbo_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
} else {
- rdlen = rx_ring->count *
- sizeof(struct e1000_rx_desc);
+ rdlen = rx_ring->count * sizeof(struct e1000_rx_desc);
adapter->clean_rx = e1000_clean_rx_irq;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
}
@@ -1885,8 +2163,21 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
* units), e.g. using jumbo frames when setting to E1000_ERT_2048
*/
if ((adapter->flags & FLAG_HAS_ERT) &&
- (adapter->netdev->mtu > ETH_DATA_LEN))
- ew32(ERT, E1000_ERT_2048);
+ (adapter->netdev->mtu > ETH_DATA_LEN)) {
+ u32 rxdctl = er32(RXDCTL(0));
+ ew32(RXDCTL(0), rxdctl | 0x3);
+ ew32(ERT, E1000_ERT_2048 | (1 << 13));
+ /*
+ * With jumbo frames and early-receive enabled, excessive
+ * C4->C2 latencies result in dropped transactions.
+ */
+ pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
+ e1000e_driver_name, 55);
+ } else {
+ pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
+ e1000e_driver_name,
+ PM_QOS_DEFAULT_VALUE);
+ }
/* Enable Receives */
ew32(RCTL, rctl);
@@ -2155,6 +2446,14 @@ void e1000e_reset(struct e1000_adapter *adapter)
/* Allow time for pending master requests to run */
mac->ops.reset_hw(hw);
+
+ /*
+ * For parts with AMT enabled, let the firmware know
+ * that the network interface is in control
+ */
+ if ((adapter->flags & FLAG_HAS_AMT) && e1000e_check_mng_mode(hw))
+ e1000_get_hw_control(adapter);
+
ew32(WUC, 0);
if (mac->ops.init_hw(hw))
@@ -3469,6 +3768,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
* means we reserve 2 more, this pushes us to allocate from the next
* larger slab size.
* i.e. RXBUFFER_2048 --> size-4096 slab
+ * However with the new *_jumbo_rx* routines, jumbo receives will use
+ * fragmented skbs
*/
if (max_frame <= 256)
@@ -3626,6 +3927,9 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
ew32(CTRL_EXT, ctrl_ext);
}
+ if (adapter->flags & FLAG_IS_ICH)
+ e1000e_disable_gig_wol_ich8lan(&adapter->hw);
+
/* Allow time for pending master requests to run */
e1000e_disable_pcie_master(&adapter->hw);
@@ -4292,6 +4596,13 @@ static struct pci_device_id e1000_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan },
+
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan },
{ } /* terminate list */
};
@@ -4326,7 +4637,9 @@ static int __init e1000_init_module(void)
printk(KERN_INFO "%s: Copyright (c) 1999-2008 Intel Corporation.\n",
e1000e_driver_name);
ret = pci_register_driver(&e1000_driver);
-
+ pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name,
+ PM_QOS_DEFAULT_VALUE);
+
return ret;
}
module_init(e1000_init_module);
@@ -4340,6 +4653,7 @@ module_init(e1000_init_module);
static void __exit e1000_exit_module(void)
{
pci_unregister_driver(&e1000_driver);
+ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name);
}
module_exit(e1000_exit_module);
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index e102332a6bee..b133dcf0e950 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -34,6 +34,9 @@ static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
static s32 e1000_wait_autoneg(struct e1000_hw *hw);
+static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
+static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
+ u16 *data, bool read);
/* Cable length tables */
static const u16 e1000_m88_cable_length_table[] =
@@ -465,6 +468,10 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
if (phy->disable_polarity_correction == 1)
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+ /* Enable downshift on BM (disabled by default) */
+ if (phy->type == e1000_phy_bm)
+ phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
+
ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
if (ret_val)
return ret_val;
@@ -1776,6 +1783,10 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
case IFE_C_E_PHY_ID:
phy_type = e1000_phy_ife;
break;
+ case BME1000_E_PHY_ID:
+ case BME1000_E_PHY_ID_R2:
+ phy_type = e1000_phy_bm;
+ break;
default:
phy_type = e1000_phy_unknown;
break;
@@ -1784,6 +1795,273 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
}
/**
+ * e1000e_determine_phy_address - Determines PHY address.
+ * @hw: pointer to the HW structure
+ *
+ * This uses a trial and error method to loop through possible PHY
+ * addresses. It tests each by reading the PHY ID registers and
+ * checking for a match.
+ **/
+s32 e1000e_determine_phy_address(struct e1000_hw *hw)
+{
+ s32 ret_val = -E1000_ERR_PHY_TYPE;
+ u32 phy_addr= 0;
+ u32 i = 0;
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ do {
+ for (phy_addr = 0; phy_addr < 4; phy_addr++) {
+ hw->phy.addr = phy_addr;
+ e1000e_get_phy_id(hw);
+ phy_type = e1000e_get_phy_type_from_id(hw->phy.id);
+
+ /*
+ * If phy_type is valid, break - we found our
+ * PHY address
+ */
+ if (phy_type != e1000_phy_unknown) {
+ ret_val = 0;
+ break;
+ }
+ }
+ i++;
+ } while ((ret_val != 0) && (i < 100));
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_phy_addr_for_bm_page - Retrieve PHY page address
+ * @page: page to access
+ *
+ * Returns the phy address for the page requested.
+ **/
+static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg)
+{
+ u32 phy_addr = 2;
+
+ if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
+ phy_addr = 1;
+
+ return phy_addr;
+}
+
+/**
+ * e1000e_write_phy_reg_bm - Write BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+ u32 page_select = 0;
+ u32 page = offset >> IGP_PAGE_SHIFT;
+ u32 page_shift = 0;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+ false);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
+
+ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /*
+ * Page select is register 31 for phy address 1 and 22 for
+ * phy address 2 and 3. Page select is shifted only for
+ * phy address 1.
+ */
+ if (hw->phy.addr == 1) {
+ page_shift = IGP_PAGE_SHIFT;
+ page_select = IGP01E1000_PHY_PAGE_SELECT;
+ } else {
+ page_shift = 0;
+ page_select = BM_PHY_PAGE_SELECT;
+ }
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
+ (page << page_shift));
+ if (ret_val) {
+ hw->phy.ops.release_phy(hw);
+ goto out;
+ }
+ }
+
+ ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000e_read_phy_reg_bm - Read BM PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+ u32 page_select = 0;
+ u32 page = offset >> IGP_PAGE_SHIFT;
+ u32 page_shift = 0;
+
+ /* Page 800 works differently than the rest so it has its own func */
+ if (page == BM_WUC_PAGE) {
+ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+ true);
+ goto out;
+ }
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
+
+ hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ /*
+ * Page select is register 31 for phy address 1 and 22 for
+ * phy address 2 and 3. Page select is shifted only for
+ * phy address 1.
+ */
+ if (hw->phy.addr == 1) {
+ page_shift = IGP_PAGE_SHIFT;
+ page_select = IGP01E1000_PHY_PAGE_SELECT;
+ } else {
+ page_shift = 0;
+ page_select = BM_PHY_PAGE_SELECT;
+ }
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
+ (page << page_shift));
+ if (ret_val) {
+ hw->phy.ops.release_phy(hw);
+ goto out;
+ }
+ }
+
+ ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
+ hw->phy.ops.release_phy(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read or written
+ * @data: pointer to the data to read or write
+ * @read: determines if operation is read or write
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting. Note that procedure to read the wakeup
+ * registers are different. It works as such:
+ * 1) Set page 769, register 17, bit 2 = 1
+ * 2) Set page to 800 for host (801 if we were manageability)
+ * 3) Write the address using the address opcode (0x11)
+ * 4) Read or write the data using the data opcode (0x12)
+ * 5) Restore 769_17.2 to its original value
+ **/
+static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
+ u16 *data, bool read)
+{
+ s32 ret_val;
+ u16 reg = ((u16)offset) & PHY_REG_MASK;
+ u16 phy_reg = 0;
+ u8 phy_acquired = 1;
+
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val) {
+ phy_acquired = 0;
+ goto out;
+ }
+
+ /* All operations in this function are phy address 1 */
+ hw->phy.addr = 1;
+
+ /* Set page 769 */
+ e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+ ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
+ if (ret_val)
+ goto out;
+
+ /* First clear bit 4 to avoid a power state change */
+ phy_reg &= ~(BM_WUC_HOST_WU_BIT);
+ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+ if (ret_val)
+ goto out;
+
+ /* Write bit 2 = 1, and clear bit 4 to 769_17 */
+ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
+ phy_reg | BM_WUC_ENABLE_BIT);
+ if (ret_val)
+ goto out;
+
+ /* Select page 800 */
+ ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_PAGE << IGP_PAGE_SHIFT));
+
+ /* Write the page 800 offset value using opcode 0x11 */
+ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
+ if (ret_val)
+ goto out;
+
+ if (read) {
+ /* Read the page 800 value using opcode 0x12 */
+ ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+ data);
+ } else {
+ /* Read the page 800 value using opcode 0x12 */
+ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+ *data);
+ }
+
+ if (ret_val)
+ goto out;
+
+ /*
+ * Restore 769_17.2 to its original value
+ * Set page 769
+ */
+ e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+ /* Clear 769_17.2 */
+ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+
+out:
+ if (phy_acquired == 1)
+ hw->phy.ops.release_phy(hw);
+ return ret_val;
+}
+
+/**
* e1000e_commit_phy - Soft PHY reset
* @hw: pointer to the HW structure
*
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 83bda6ccde98..56f50491a453 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -633,7 +633,7 @@ static void __init printEEPROMInfo(struct net_device *dev)
printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
- printk(KERN_DEBUG " AutoPort: %d\n", GetBit(!Word,ee_Jabber));
+ printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 2eb82aba4a8b..795c594a4b7c 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -202,7 +202,7 @@ static unsigned short start_code[] = {
0x0000,Cmd_MCast,
0x0076, /* link to next command */
#define CONF_NR_MULTICAST 0x44
- 0x0000, /* number of multicast addresses */
+ 0x0000, /* number of bytes in multicast address(es) */
#define CONF_MULTICAST 0x46
0x0000, 0x0000, 0x0000, /* some addresses */
0x0000, 0x0000, 0x0000,
@@ -1569,7 +1569,7 @@ static void eexp_hw_init586(struct net_device *dev)
static void eexp_setup_filter(struct net_device *dev)
{
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
unsigned short ioaddr = dev->base_addr;
int count = dev->mc_count;
int i;
@@ -1580,9 +1580,9 @@ static void eexp_setup_filter(struct net_device *dev)
}
outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
- outw(count, ioaddr+SHADOW(CONF_NR_MULTICAST));
- for (i = 0; i < count; i++) {
- unsigned short *data = (unsigned short *)dmi->dmi_addr;
+ outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
+ for (i = 0, dmi = dev->mc_list; i < count; i++, dmi = dmi->next) {
+ unsigned short *data;
if (!dmi) {
printk(KERN_INFO "%s: too few multicast addresses\n", dev->name);
break;
@@ -1591,6 +1591,7 @@ static void eexp_setup_filter(struct net_device *dev)
printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
continue;
}
+ data = (unsigned short *)dmi->dmi_addr;
outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index f5dacceab95b..fe872fbd671e 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0090"
+#define DRV_VERSION "EHEA_0091"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
@@ -118,6 +118,13 @@
#define EHEA_MR_ACC_CTRL 0x00800000
#define EHEA_BUSMAP_START 0x8000000000000000ULL
+#define EHEA_INVAL_ADDR 0xFFFFFFFFFFFFFFFFULL
+#define EHEA_DIR_INDEX_SHIFT 13 /* 8k Entries in 64k block */
+#define EHEA_TOP_INDEX_SHIFT (EHEA_DIR_INDEX_SHIFT * 2)
+#define EHEA_MAP_ENTRIES (1 << EHEA_DIR_INDEX_SHIFT)
+#define EHEA_MAP_SIZE (0x10000) /* currently fixed map size */
+#define EHEA_INDEX_MASK (EHEA_MAP_ENTRIES - 1)
+
#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
@@ -192,10 +199,20 @@ struct h_epas {
set to 0 if unused */
};
-struct ehea_busmap {
- unsigned int entries; /* total number of entries */
- unsigned int valid_sections; /* number of valid sections */
- u64 *vaddr;
+/*
+ * Memory map data structures
+ */
+struct ehea_dir_bmap
+{
+ u64 ent[EHEA_MAP_ENTRIES];
+};
+struct ehea_top_bmap
+{
+ struct ehea_dir_bmap *dir[EHEA_MAP_ENTRIES];
+};
+struct ehea_bmap
+{
+ struct ehea_top_bmap *top[EHEA_MAP_ENTRIES];
};
struct ehea_qp;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index f9bc21c74b59..d1b6d4e7495d 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -35,6 +35,7 @@
#include <linux/if_ether.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
+#include <linux/memory.h>
#include <asm/kexec.h>
#include <linux/mutex.h>
@@ -3503,6 +3504,24 @@ void ehea_crash_handler(void)
0, H_DEREG_BCMC);
}
+static int ehea_mem_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ switch (action) {
+ case MEM_OFFLINE:
+ ehea_info("memory has been removed");
+ ehea_rereg_mrs(NULL);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ehea_mem_nb = {
+ .notifier_call = ehea_mem_notifier,
+};
+
static int ehea_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
@@ -3581,6 +3600,10 @@ int __init ehea_module_init(void)
if (ret)
ehea_info("failed registering reboot notifier");
+ ret = register_memory_notifier(&ehea_mem_nb);
+ if (ret)
+ ehea_info("failed registering memory remove notifier");
+
ret = crash_shutdown_register(&ehea_crash_handler);
if (ret)
ehea_info("failed registering crash handler");
@@ -3604,6 +3627,7 @@ int __init ehea_module_init(void)
out3:
ibmebus_unregister_driver(&ehea_driver);
out2:
+ unregister_memory_notifier(&ehea_mem_nb);
unregister_reboot_notifier(&ehea_reboot_nb);
crash_shutdown_unregister(&ehea_crash_handler);
out:
@@ -3621,6 +3645,7 @@ static void __exit ehea_module_exit(void)
ret = crash_shutdown_unregister(&ehea_crash_handler);
if (ret)
ehea_info("failed unregistering crash handler");
+ unregister_memory_notifier(&ehea_mem_nb);
kfree(ehea_fw_handles.arr);
kfree(ehea_bcmc_regs.arr);
ehea_destroy_busmap();
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index d522e905f460..140f05baafd8 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -31,8 +31,8 @@
#include "ehea_phyp.h"
#include "ehea_qmr.h"
+struct ehea_bmap *ehea_bmap = NULL;
-struct ehea_busmap ehea_bmap = { 0, 0, NULL };
static void *hw_qpageit_get_inc(struct hw_queue *queue)
@@ -559,125 +559,253 @@ int ehea_destroy_qp(struct ehea_qp *qp)
return 0;
}
-int ehea_create_busmap(void)
+static inline int ehea_calc_index(unsigned long i, unsigned long s)
{
- u64 vaddr = EHEA_BUSMAP_START;
- unsigned long high_section_index = 0;
- int i;
+ return (i >> s) & EHEA_INDEX_MASK;
+}
- /*
- * Sections are not in ascending order -> Loop over all sections and
- * find the highest PFN to compute the required map size.
- */
- ehea_bmap.valid_sections = 0;
+static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap,
+ int dir)
+{
+ if(!ehea_top_bmap->dir[dir]) {
+ ehea_top_bmap->dir[dir] =
+ kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL);
+ if (!ehea_top_bmap->dir[dir])
+ return -ENOMEM;
+ }
+ return 0;
+}
- for (i = 0; i < NR_MEM_SECTIONS; i++)
- if (valid_section_nr(i))
- high_section_index = i;
+static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir)
+{
+ if(!ehea_bmap->top[top]) {
+ ehea_bmap->top[top] =
+ kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL);
+ if (!ehea_bmap->top[top])
+ return -ENOMEM;
+ }
+ return ehea_init_top_bmap(ehea_bmap->top[top], dir);
+}
- ehea_bmap.entries = high_section_index + 1;
- ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
+static int ehea_create_busmap_callback(unsigned long pfn,
+ unsigned long nr_pages, void *arg)
+{
+ unsigned long i, mr_len, start_section, end_section;
+ start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE;
+ end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE);
+ mr_len = *(unsigned long *)arg;
- if (!ehea_bmap.vaddr)
+ ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
+ if (!ehea_bmap)
return -ENOMEM;
- for (i = 0 ; i < ehea_bmap.entries; i++) {
- unsigned long pfn = section_nr_to_pfn(i);
+ for (i = start_section; i < end_section; i++) {
+ int ret;
+ int top, dir, idx;
+ u64 vaddr;
+
+ top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
+ dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
+
+ ret = ehea_init_bmap(ehea_bmap, top, dir);
+ if(ret)
+ return ret;
- if (pfn_valid(pfn)) {
- ehea_bmap.vaddr[i] = vaddr;
- vaddr += EHEA_SECTSIZE;
- ehea_bmap.valid_sections++;
- } else
- ehea_bmap.vaddr[i] = 0;
+ idx = i & EHEA_INDEX_MASK;
+ vaddr = EHEA_BUSMAP_START + mr_len + i * EHEA_SECTSIZE;
+
+ ehea_bmap->top[top]->dir[dir]->ent[idx] = vaddr;
}
+ mr_len += nr_pages * PAGE_SIZE;
+ *(unsigned long *)arg = mr_len;
+
return 0;
}
+static unsigned long ehea_mr_len;
+
+static DEFINE_MUTEX(ehea_busmap_mutex);
+
+int ehea_create_busmap(void)
+{
+ int ret;
+ mutex_lock(&ehea_busmap_mutex);
+ ehea_mr_len = 0;
+ ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, &ehea_mr_len,
+ ehea_create_busmap_callback);
+ mutex_unlock(&ehea_busmap_mutex);
+ return ret;
+}
+
void ehea_destroy_busmap(void)
{
- vfree(ehea_bmap.vaddr);
+ int top, dir;
+ mutex_lock(&ehea_busmap_mutex);
+ if (!ehea_bmap)
+ goto out_destroy;
+
+ for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
+ if (!ehea_bmap->top[top])
+ continue;
+
+ for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
+ if (!ehea_bmap->top[top]->dir[dir])
+ continue;
+
+ kfree(ehea_bmap->top[top]->dir[dir]);
+ }
+
+ kfree(ehea_bmap->top[top]);
+ }
+
+ kfree(ehea_bmap);
+ ehea_bmap = NULL;
+out_destroy:
+ mutex_unlock(&ehea_busmap_mutex);
}
u64 ehea_map_vaddr(void *caddr)
{
- u64 mapped_addr;
- unsigned long index = __pa(caddr) >> SECTION_SIZE_BITS;
-
- if (likely(index < ehea_bmap.entries)) {
- mapped_addr = ehea_bmap.vaddr[index];
- if (likely(mapped_addr))
- mapped_addr |= (((unsigned long)caddr)
- & (EHEA_SECTSIZE - 1));
- else
- mapped_addr = -1;
- } else
- mapped_addr = -1;
-
- if (unlikely(mapped_addr == -1))
- if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
- schedule_work(&ehea_rereg_mr_task);
-
- return mapped_addr;
+ int top, dir, idx;
+ unsigned long index, offset;
+
+ if (!ehea_bmap)
+ return EHEA_INVAL_ADDR;
+
+ index = virt_to_abs(caddr) >> SECTION_SIZE_BITS;
+ top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK;
+ if (!ehea_bmap->top[top])
+ return EHEA_INVAL_ADDR;
+
+ dir = (index >> EHEA_DIR_INDEX_SHIFT) & EHEA_INDEX_MASK;
+ if (!ehea_bmap->top[top]->dir[dir])
+ return EHEA_INVAL_ADDR;
+
+ idx = index & EHEA_INDEX_MASK;
+ if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
+ return EHEA_INVAL_ADDR;
+
+ offset = (unsigned long)caddr & (EHEA_SECTSIZE - 1);
+ return ehea_bmap->top[top]->dir[dir]->ent[idx] | offset;
+}
+
+static inline void *ehea_calc_sectbase(int top, int dir, int idx)
+{
+ unsigned long ret = idx;
+ ret |= dir << EHEA_DIR_INDEX_SHIFT;
+ ret |= top << EHEA_TOP_INDEX_SHIFT;
+ return abs_to_virt(ret << SECTION_SIZE_BITS);
+}
+
+static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
+ struct ehea_adapter *adapter,
+ struct ehea_mr *mr)
+{
+ void *pg;
+ u64 j, m, hret;
+ unsigned long k = 0;
+ u64 pt_abs = virt_to_abs(pt);
+
+ void *sectbase = ehea_calc_sectbase(top, dir, idx);
+
+ for (j = 0; j < (EHEA_PAGES_PER_SECTION / EHEA_MAX_RPAGE); j++) {
+
+ for (m = 0; m < EHEA_MAX_RPAGE; m++) {
+ pg = sectbase + ((k++) * EHEA_PAGESIZE);
+ pt[m] = virt_to_abs(pg);
+ }
+ hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0,
+ 0, pt_abs, EHEA_MAX_RPAGE);
+
+ if ((hret != H_SUCCESS)
+ && (hret != H_PAGE_REGISTERED)) {
+ ehea_h_free_resource(adapter->handle, mr->handle,
+ FORCE_FREE);
+ ehea_error("register_rpage_mr failed");
+ return hret;
+ }
+ }
+ return hret;
+}
+
+static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt,
+ struct ehea_adapter *adapter,
+ struct ehea_mr *mr)
+{
+ u64 hret = H_SUCCESS;
+ int idx;
+
+ for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
+ if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
+ continue;
+
+ hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
+ if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+ return hret;
+ }
+ return hret;
+}
+
+static u64 ehea_reg_mr_dir_sections(int top, u64 *pt,
+ struct ehea_adapter *adapter,
+ struct ehea_mr *mr)
+{
+ u64 hret = H_SUCCESS;
+ int dir;
+
+ for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
+ if (!ehea_bmap->top[top]->dir[dir])
+ continue;
+
+ hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
+ if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
+ return hret;
+ }
+ return hret;
}
int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
{
int ret;
u64 *pt;
- void *pg;
- u64 hret, pt_abs, i, j, m, mr_len;
+ u64 hret;
u32 acc_ctrl = EHEA_MR_ACC_CTRL;
- mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
+ unsigned long top;
- pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!pt) {
ehea_error("no mem");
ret = -ENOMEM;
goto out;
}
- pt_abs = virt_to_abs(pt);
- hret = ehea_h_alloc_resource_mr(adapter->handle,
- EHEA_BUSMAP_START, mr_len,
- acc_ctrl, adapter->pd,
+ hret = ehea_h_alloc_resource_mr(adapter->handle, EHEA_BUSMAP_START,
+ ehea_mr_len, acc_ctrl, adapter->pd,
&mr->handle, &mr->lkey);
+
if (hret != H_SUCCESS) {
ehea_error("alloc_resource_mr failed");
ret = -EIO;
goto out;
}
- for (i = 0 ; i < ehea_bmap.entries; i++)
- if (ehea_bmap.vaddr[i]) {
- void *sectbase = __va(i << SECTION_SIZE_BITS);
- unsigned long k = 0;
-
- for (j = 0; j < (EHEA_PAGES_PER_SECTION /
- EHEA_MAX_RPAGE); j++) {
-
- for (m = 0; m < EHEA_MAX_RPAGE; m++) {
- pg = sectbase + ((k++) * EHEA_PAGESIZE);
- pt[m] = virt_to_abs(pg);
- }
-
- hret = ehea_h_register_rpage_mr(adapter->handle,
- mr->handle,
- 0, 0, pt_abs,
- EHEA_MAX_RPAGE);
- if ((hret != H_SUCCESS)
- && (hret != H_PAGE_REGISTERED)) {
- ehea_h_free_resource(adapter->handle,
- mr->handle,
- FORCE_FREE);
- ehea_error("register_rpage_mr failed");
- ret = -EIO;
- goto out;
- }
- }
- }
+ if (!ehea_bmap) {
+ ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
+ ehea_error("no busmap available");
+ ret = -EIO;
+ goto out;
+ }
+
+ for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
+ if (!ehea_bmap->top[top])
+ continue;
+
+ hret = ehea_reg_mr_dir_sections(top, pt, adapter, mr);
+ if((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
+ break;
+ }
if (hret != H_SUCCESS) {
ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d7a3ea88eddb..32a4f17d35fc 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -67,6 +67,10 @@
#define FEC_MAX_PORTS 1
#endif
+#if defined(CONFIG_FADS) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_M5272)
+#define HAVE_mii_link_interrupt
+#endif
+
/*
* Define the fixed address of the FEC hardware.
*/
@@ -205,7 +209,10 @@ struct fec_enet_private {
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
uint tx_full;
- spinlock_t lock;
+ /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+ spinlock_t hw_lock;
+ /* hold while accessing the mii_list_t() elements */
+ spinlock_t mii_lock;
uint phy_id;
uint phy_id_done;
@@ -309,6 +316,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
volatile fec_t *fecp;
volatile cbd_t *bdp;
unsigned short status;
+ unsigned long flags;
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
@@ -318,6 +326,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
+ spin_lock_irqsave(&fep->hw_lock, flags);
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
@@ -328,6 +337,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
* This should not happen, since dev->tbusy should be set.
*/
printk("%s: tx queue full!.\n", dev->name);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 1;
}
#endif
@@ -366,8 +376,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
flush_dcache_range((unsigned long)skb->data,
(unsigned long)skb->data + skb->len);
- spin_lock_irq(&fep->lock);
-
/* Send it on its way. Tell FEC it's ready, interrupt when done,
* it's the last BD of the frame, and to put the CRC on the end.
*/
@@ -396,7 +404,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
fep->cur_tx = (cbd_t *)bdp;
- spin_unlock_irq(&fep->lock);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 0;
}
@@ -454,19 +462,20 @@ fec_enet_interrupt(int irq, void * dev_id)
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
- int handled = 0;
+ irqreturn_t ret = IRQ_NONE;
fecp = (volatile fec_t*)dev->base_addr;
/* Get the interrupt events that caused us to be here.
*/
- while ((int_events = fecp->fec_ievent) != 0) {
+ do {
+ int_events = fecp->fec_ievent;
fecp->fec_ievent = int_events;
/* Handle receive event in its own function.
*/
if (int_events & FEC_ENET_RXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_rx(dev);
}
@@ -475,17 +484,18 @@ fec_enet_interrupt(int irq, void * dev_id)
them as part of the transmit process.
*/
if (int_events & FEC_ENET_TXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_tx(dev);
}
if (int_events & FEC_ENET_MII) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_mii(dev);
}
- }
- return IRQ_RETVAL(handled);
+ } while (int_events);
+
+ return ret;
}
@@ -498,7 +508,7 @@ fec_enet_tx(struct net_device *dev)
struct sk_buff *skb;
fep = netdev_priv(dev);
- spin_lock(&fep->lock);
+ spin_lock_irq(&fep->hw_lock);
bdp = fep->dirty_tx;
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
@@ -557,7 +567,7 @@ fec_enet_tx(struct net_device *dev)
}
}
fep->dirty_tx = (cbd_t *)bdp;
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->hw_lock);
}
@@ -584,6 +594,8 @@ fec_enet_rx(struct net_device *dev)
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
+ spin_lock_irq(&fep->hw_lock);
+
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
@@ -689,6 +701,8 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
*/
fecp->fec_r_des_active = 0;
#endif
+
+ spin_unlock_irq(&fep->hw_lock);
}
@@ -702,11 +716,11 @@ fec_enet_mii(struct net_device *dev)
uint mii_reg;
fep = netdev_priv(dev);
+ spin_lock_irq(&fep->mii_lock);
+
ep = fep->hwp;
mii_reg = ep->fec_mii_data;
- spin_lock(&fep->lock);
-
if ((mip = mii_head) == NULL) {
printk("MII and no head!\n");
goto unlock;
@@ -723,7 +737,7 @@ fec_enet_mii(struct net_device *dev)
ep->fec_mii_data = mip->mii_regval;
unlock:
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->mii_lock);
}
static int
@@ -737,12 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
/* Add PHY address to register command.
*/
fep = netdev_priv(dev);
- regval |= fep->phy_addr << 23;
+ spin_lock_irqsave(&fep->mii_lock, flags);
+ regval |= fep->phy_addr << 23;
retval = 0;
- spin_lock_irqsave(&fep->lock,flags);
-
if ((mip = mii_free) != NULL) {
mii_free = mip->mii_next;
mip->mii_regval = regval;
@@ -759,9 +772,8 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
retval = 1;
}
- spin_unlock_irqrestore(&fep->lock,flags);
-
- return(retval);
+ spin_unlock_irqrestore(&fep->mii_lock, flags);
+ return retval;
}
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
@@ -1222,7 +1234,7 @@ static phy_info_t const * const phy_info[] = {
};
/* ------------------------------------------------------------------------- */
-#if !defined(CONFIG_M532x)
+#ifdef HAVE_mii_link_interrupt
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id);
@@ -1362,18 +1374,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 23 },
- { "fec(TXB)", 24 },
- { "fec(TXFIFO)", 25 },
- { "fec(TXCR)", 26 },
{ "fec(RXF)", 27 },
- { "fec(RXB)", 28 },
{ "fec(MII)", 29 },
- { "fec(LC)", 30 },
- { "fec(HBERR)", 31 },
- { "fec(GRA)", 32 },
- { "fec(EBERR)", 33 },
- { "fec(BABT)", 34 },
- { "fec(BABR)", 35 },
{ NULL },
};
@@ -1533,18 +1535,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 23 },
- { "fec(TXB)", 24 },
- { "fec(TXFIFO)", 25 },
- { "fec(TXCR)", 26 },
{ "fec(RXF)", 27 },
- { "fec(RXB)", 28 },
{ "fec(MII)", 29 },
- { "fec(LC)", 30 },
- { "fec(HBERR)", 31 },
- { "fec(GRA)", 32 },
- { "fec(EBERR)", 33 },
- { "fec(BABT)", 34 },
- { "fec(BABR)", 35 },
{ NULL },
};
@@ -1660,18 +1652,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 36 },
- { "fec(TXB)", 37 },
- { "fec(TXFIFO)", 38 },
- { "fec(TXCR)", 39 },
{ "fec(RXF)", 40 },
- { "fec(RXB)", 41 },
{ "fec(MII)", 42 },
- { "fec(LC)", 43 },
- { "fec(HBERR)", 44 },
- { "fec(GRA)", 45 },
- { "fec(EBERR)", 46 },
- { "fec(BABT)", 47 },
- { "fec(BABR)", 48 },
{ NULL },
};
@@ -2126,6 +2108,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
/* This interrupt occurs when the PHY detects a link change.
*/
+#ifdef HAVE_mii_link_interrupt
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id)
@@ -2148,6 +2131,7 @@ mii_link_interrupt(int irq, void * dev_id)
return IRQ_HANDLED;
}
+#endif
static int
fec_enet_open(struct net_device *dev)
@@ -2243,13 +2227,13 @@ static void set_multicast_list(struct net_device *dev)
/* Catch all multicast addresses, so set the
* filter to all 1's.
*/
- ep->fec_hash_table_high = 0xffffffff;
- ep->fec_hash_table_low = 0xffffffff;
+ ep->fec_grp_hash_table_high = 0xffffffff;
+ ep->fec_grp_hash_table_low = 0xffffffff;
} else {
/* Clear filter and add the addresses in hash register.
*/
- ep->fec_hash_table_high = 0;
- ep->fec_hash_table_low = 0;
+ ep->fec_grp_hash_table_high = 0;
+ ep->fec_grp_hash_table_low = 0;
dmi = dev->mc_list;
@@ -2280,9 +2264,9 @@ static void set_multicast_list(struct net_device *dev)
hash = (crc >> (32 - HASH_BITS)) & 0x3f;
if (hash > 31)
- ep->fec_hash_table_high |= 1 << (hash - 32);
+ ep->fec_grp_hash_table_high |= 1 << (hash - 32);
else
- ep->fec_hash_table_low |= 1 << hash;
+ ep->fec_grp_hash_table_low |= 1 << hash;
}
}
}
@@ -2332,6 +2316,9 @@ int __init fec_enet_init(struct net_device *dev)
return -ENOMEM;
}
+ spin_lock_init(&fep->hw_lock);
+ spin_lock_init(&fep->mii_lock);
+
/* Create an Ethernet device instance.
*/
fecp = (volatile fec_t *) fec_hw[index];
@@ -2430,11 +2417,15 @@ int __init fec_enet_init(struct net_device *dev)
*/
fec_request_intrs(dev);
- fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_grp_hash_table_high = 0;
+ fecp->fec_grp_hash_table_low = 0;
fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
fecp->fec_ecntrl = 2;
fecp->fec_r_des_active = 0;
+#ifndef CONFIG_M5272
+ fecp->fec_hash_table_high = 0;
+ fecp->fec_hash_table_low = 0;
+#endif
dev->base_addr = (unsigned long)fecp;
@@ -2455,8 +2446,7 @@ int __init fec_enet_init(struct net_device *dev)
/* Clear and enable interrupts */
fecp->fec_ievent = 0xffc00000;
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
/* Queue up command to detect the PHY and initialize the
* remainder of the interface.
@@ -2500,8 +2490,8 @@ fec_restart(struct net_device *dev, int duplex)
/* Reset all multicast.
*/
- fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_grp_hash_table_high = 0;
+ fecp->fec_grp_hash_table_low = 0;
/* Set maximum receive buffer size.
*/
@@ -2583,8 +2573,7 @@ fec_restart(struct net_device *dev, int duplex)
/* Enable interrupts we wish to service.
*/
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
}
static void
@@ -2624,7 +2613,7 @@ fec_stop(struct net_device *dev)
static int __init fec_enet_module_init(void)
{
struct net_device *dev;
- int i, j, err;
+ int i, err;
DECLARE_MAC_BUF(mac);
printk("FEC ENET Version 0.2\n");
diff --git a/drivers/net/fec.h b/drivers/net/fec.h
index 1d421606984f..292719daceff 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/fec.h
@@ -88,8 +88,8 @@ typedef struct fec {
unsigned long fec_reserved7[158];
unsigned long fec_addr_low; /* Low 32bits MAC address */
unsigned long fec_addr_high; /* High 16bits MAC address */
- unsigned long fec_hash_table_high; /* High 32bits hash table */
- unsigned long fec_hash_table_low; /* Low 32bits hash table */
+ unsigned long fec_grp_hash_table_high;/* High 32bits hash table */
+ unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */
unsigned long fec_r_des_start; /* Receive descriptor ring */
unsigned long fec_x_des_start; /* Transmit descriptor ring */
unsigned long fec_r_buff_size; /* Maximum receive buff size */
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index e5e6352556fa..5f9c42e7a7f1 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -43,6 +43,29 @@
#define DRIVER_NAME "mpc52xx-fec"
+#define FEC5200_PHYADDR_NONE (-1)
+#define FEC5200_PHYADDR_7WIRE (-2)
+
+/* Private driver data structure */
+struct mpc52xx_fec_priv {
+ int duplex;
+ int speed;
+ int r_irq;
+ int t_irq;
+ struct mpc52xx_fec __iomem *fec;
+ struct bcom_task *rx_dmatsk;
+ struct bcom_task *tx_dmatsk;
+ spinlock_t lock;
+ int msg_enable;
+
+ /* MDIO link details */
+ int phy_addr;
+ unsigned int phy_speed;
+ struct phy_device *phydev;
+ enum phy_state link;
+};
+
+
static irqreturn_t mpc52xx_fec_interrupt(int, void *);
static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
@@ -223,7 +246,7 @@ static int mpc52xx_fec_phy_start(struct net_device *dev)
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
int err;
- if (!priv->has_phy)
+ if (priv->phy_addr < 0)
return 0;
err = mpc52xx_fec_init_phy(dev);
@@ -243,7 +266,7 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
- if (!priv->has_phy)
+ if (!priv->phydev)
return;
phy_disconnect(priv->phydev);
@@ -255,7 +278,7 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
struct mii_ioctl_data *mii_data, int cmd)
{
- if (!priv->has_phy)
+ if (!priv->phydev)
return -ENOTSUPP;
return phy_mii_ioctl(priv->phydev, mii_data, cmd);
@@ -265,7 +288,7 @@ static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
{
struct mpc52xx_fec __iomem *fec = priv->fec;
- if (!priv->has_phy)
+ if (priv->phydev)
return;
out_be32(&fec->mii_speed, priv->phy_speed);
@@ -491,20 +514,23 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
out_be32(&fec->ievent, ievent); /* clear pending events */
- if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
- if (ievent & ~FEC_IEVENT_TFINT)
- dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
+ /* on fifo error, soft-reset fec */
+ if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+
+ if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
+ if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+
+ mpc52xx_fec_reset(dev);
+
+ netif_wake_queue(dev);
return IRQ_HANDLED;
}
- if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
- dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
- if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
- dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
-
- mpc52xx_fec_reset(dev);
+ if (ievent & ~FEC_IEVENT_TFINT)
+ dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
- netif_wake_queue(dev);
return IRQ_HANDLED;
}
@@ -701,7 +727,7 @@ static void mpc52xx_fec_start(struct net_device *dev)
rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
rcntrl |= FEC_RCNTRL_FCE;
- if (priv->has_phy)
+ if (priv->phy_addr != FEC5200_PHYADDR_7WIRE)
rcntrl |= FEC_RCNTRL_MII_MODE;
if (priv->duplex == DUPLEX_FULL)
@@ -861,7 +887,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
struct net_device *ndev;
struct mpc52xx_fec_priv *priv = NULL;
struct resource mem;
- const phandle *ph;
+ struct device_node *phy_node;
+ const phandle *phy_handle;
+ const u32 *prop;
+ int prop_size;
phys_addr_t rx_fifo;
phys_addr_t tx_fifo;
@@ -945,26 +974,37 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
- priv->duplex = DUPLEX_FULL;
- /* is the phy present in device tree? */
- ph = of_get_property(op->node, "phy-handle", NULL);
- if (ph) {
- const unsigned int *prop;
- struct device_node *phy_dn;
- priv->has_phy = 1;
-
- phy_dn = of_find_node_by_phandle(*ph);
- prop = of_get_property(phy_dn, "reg", NULL);
- priv->phy_addr = *prop;
+ /*
+ * Link mode configuration
+ */
- of_node_put(phy_dn);
+ /* Start with safe defaults for link connection */
+ priv->phy_addr = FEC5200_PHYADDR_NONE;
+ priv->speed = 100;
+ priv->duplex = DUPLEX_HALF;
+ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+
+ /* the 7-wire property means don't use MII mode */
+ if (of_find_property(op->node, "fsl,7-wire-mode", NULL))
+ priv->phy_addr = FEC5200_PHYADDR_7WIRE;
+
+ /* The current speed preconfigures the speed of the MII link */
+ prop = of_get_property(op->node, "current-speed", &prop_size);
+ if (prop && (prop_size >= sizeof(u32) * 2)) {
+ priv->speed = prop[0];
+ priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
+ }
- /* Phy speed */
- priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
- } else {
- dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
- " tree, using 7-wire mode\n");
+ /* If there is a phy handle, setup link to that phy */
+ phy_handle = of_get_property(op->node, "phy-handle", &prop_size);
+ if (phy_handle && (prop_size >= sizeof(phandle))) {
+ phy_node = of_find_node_by_phandle(*phy_handle);
+ prop = of_get_property(phy_node, "reg", &prop_size);
+ if (prop && (prop_size >= sizeof(u32)))
+ if ((*prop >= 0) && (*prop < PHY_MAX_ADDR))
+ priv->phy_addr = *prop;
+ of_node_put(phy_node);
}
/* Hardware init */
@@ -979,6 +1019,20 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
if (rv < 0)
goto probe_error;
+ /* Now report the link setup */
+ switch (priv->phy_addr) {
+ case FEC5200_PHYADDR_NONE:
+ dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n",
+ priv->speed, priv->duplex ? 'F' : 'H');
+ break;
+ case FEC5200_PHYADDR_7WIRE:
+ dev_info(&ndev->dev, "using 7-wire PHY mode\n");
+ break;
+ default:
+ dev_info(&ndev->dev, "Using PHY at MDIO address %i\n",
+ priv->phy_addr);
+ }
+
/* We're done ! */
dev_set_drvdata(&op->dev, ndev);
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/fec_mpc52xx.h
index 8b1f75397b9a..a227a525bdbb 100644
--- a/drivers/net/fec_mpc52xx.h
+++ b/drivers/net/fec_mpc52xx.h
@@ -26,25 +26,6 @@
#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
-struct mpc52xx_fec_priv {
- int duplex;
- int r_irq;
- int t_irq;
- struct mpc52xx_fec __iomem *fec;
- struct bcom_task *rx_dmatsk;
- struct bcom_task *tx_dmatsk;
- spinlock_t lock;
- int msg_enable;
-
- int has_phy;
- unsigned int phy_speed;
- unsigned int phy_addr;
- struct phy_device *phydev;
- enum phy_state link;
- int speed;
-};
-
-
/* ======================================================================== */
/* Hardware register sets & bits */
/* ======================================================================== */
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index ba75efc9f5b5..f0014cfbb275 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -194,7 +194,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
ret = of_address_to_resource(ofdev->node, 0, &res);
if (ret)
- return ret;
+ goto out_res;
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start);
@@ -236,6 +236,7 @@ out_free_irqs:
kfree(new_bus->irq);
out_unmap_regs:
iounmap(fec->fecp);
+out_res:
out_fec:
kfree(fec);
out_mii:
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 99a4b990939f..25bdd0832df5 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -131,8 +131,6 @@ static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
-extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value);
-extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct napi_struct *napi, int budget);
#endif
@@ -140,6 +138,7 @@ static int gfar_poll(struct napi_struct *napi, int budget);
static void gfar_netpoll(struct net_device *dev);
#endif
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+static int gfar_clean_tx_ring(struct net_device *dev);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
static void gfar_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp);
@@ -477,24 +476,30 @@ static int init_phy(struct net_device *dev)
return 0;
}
+/*
+ * Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip. We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the TBIPA register. We assume
+ * that the TBIPA register is valid. Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
static void gfar_configure_serdes(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_mii __iomem *regs =
(void __iomem *)&priv->regs->gfar_mii_regs;
+ int tbipa = gfar_read(&priv->regs->tbipa);
- /* Initialise TBI i/f to communicate with serdes (lynx phy) */
-
- /* Single clk mode, mii mode off(for aerdes communication) */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
+ /* Single clk mode, mii mode off(for serdes communication) */
+ gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT);
- /* Supported pause and full-duplex, no half-duplex */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+ gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE,
ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
ADVERTISE_1000XPSE_ASYM);
- /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+ gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE |
BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
}
@@ -541,9 +546,6 @@ static void init_registers(struct net_device *dev)
/* Initialize the Minimum Frame Length Register */
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
-
- /* Assign the TBI an address which won't conflict with the PHYs */
- gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
@@ -633,6 +635,8 @@ static void free_skb_resources(struct gfar_private *priv)
dev_kfree_skb_any(priv->tx_skbuff[i]);
priv->tx_skbuff[i] = NULL;
}
+
+ txbdp++;
}
kfree(priv->tx_skbuff);
@@ -1140,7 +1144,7 @@ static int gfar_close(struct net_device *dev)
}
/* Changes the mac address if the controller is not running. */
-int gfar_set_mac_address(struct net_device *dev)
+static int gfar_set_mac_address(struct net_device *dev)
{
gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
@@ -1259,7 +1263,7 @@ static void gfar_timeout(struct net_device *dev)
}
/* Interrupt Handler for Transmit complete */
-int gfar_clean_tx_ring(struct net_device *dev)
+static int gfar_clean_tx_ring(struct net_device *dev)
{
struct txbd8 *bdp;
struct gfar_private *priv = netdev_priv(dev);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 0d0883609469..27f37c81e52c 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -137,7 +137,6 @@ extern const char gfar_driver_version[];
#define DEFAULT_RXCOUNT 0
#endif /* CONFIG_GFAR_NAPI */
-#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
#define MIIMCFG_RESET 0x80000000
#define MIIMIND_BUSY 0x00000001
@@ -783,5 +782,8 @@ extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
int enable, u32 regnum, u32 read);
void gfar_init_sysfs(struct net_device *dev);
+int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
+ int regnum, u16 value);
+int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#endif /* __GIANFAR_H */
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index b8898927236a..ebcfb27a904e 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -78,7 +78,6 @@ int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
* same as system mdio bus, used for controlling the external PHYs, for eg.
*/
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
-
{
u16 value;
@@ -122,7 +121,7 @@ int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
}
/* Reset the MIIM registers, and wait for the bus to free */
-int gfar_mdio_reset(struct mii_bus *bus)
+static int gfar_mdio_reset(struct mii_bus *bus)
{
struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
@@ -152,14 +151,15 @@ int gfar_mdio_reset(struct mii_bus *bus)
}
-int gfar_mdio_probe(struct device *dev)
+static int gfar_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gianfar_mdio_data *pdata;
struct gfar_mii __iomem *regs;
+ struct gfar __iomem *enet_regs;
struct mii_bus *new_bus;
struct resource *r;
- int err = 0;
+ int i, err = 0;
if (NULL == dev)
return -EINVAL;
@@ -199,6 +199,34 @@ int gfar_mdio_probe(struct device *dev)
new_bus->dev = dev;
dev_set_drvdata(dev, new_bus);
+ /*
+ * This is mildly evil, but so is our hardware for doing this.
+ * Also, we have to cast back to struct gfar_mii because of
+ * definition weirdness done in gianfar.h.
+ */
+ enet_regs = (struct gfar __iomem *)
+ ((char *)regs - offsetof(struct gfar, gfar_mii_regs));
+
+ /* Scan the bus, looking for an empty spot for TBIPA */
+ gfar_write(&enet_regs->tbipa, 0);
+ for (i = PHY_MAX_ADDR; i > 0; i--) {
+ u32 phy_id;
+ int r;
+
+ r = get_phy_id(new_bus, i, &phy_id);
+ if (r)
+ return r;
+
+ if (phy_id == 0xffffffff)
+ break;
+ }
+
+ /* The bus is full. We don't support using 31 PHYs, sorry */
+ if (i == 0)
+ return -EBUSY;
+
+ gfar_write(&enet_regs->tbipa, i);
+
err = mdiobus_register(new_bus);
if (0 != err) {
@@ -218,7 +246,7 @@ reg_map_fail:
}
-int gfar_mdio_remove(struct device *dev)
+static int gfar_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index b373091c7031..2af28b16a0e2 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -41,6 +41,9 @@ struct gfar_mii {
int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
+ int regnum, u16 value);
+int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
int __init gfar_mdio_init(void);
void gfar_mdio_exit(void);
#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index 230878b94190..5116f68e01b9 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -103,10 +103,10 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
spin_lock_irqsave(&priv->rxlock, flags);
if (length > priv->rx_buffer_size)
- return count;
+ goto out;
if (length == priv->rx_stash_size)
- return count;
+ goto out;
priv->rx_stash_size = length;
@@ -125,6 +125,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
gfar_write(&priv->regs->attr, temp);
+out:
spin_unlock_irqrestore(&priv->rxlock, flags);
return count;
@@ -154,10 +155,10 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
spin_lock_irqsave(&priv->rxlock, flags);
if (index > priv->rx_stash_size)
- return count;
+ goto out;
if (index == priv->rx_stash_index)
- return count;
+ goto out;
priv->rx_stash_index = index;
@@ -166,6 +167,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
temp |= ATTRELI_EI(index);
gfar_write(&priv->regs->attreli, flags);
+out:
spin_unlock_irqrestore(&priv->rxlock, flags);
return count;
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index b53f6b6491b3..e5c2380f50ca 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1508,7 +1508,7 @@ static int hamachi_rx(struct net_device *dev)
hmp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
buf_addr = (u8 *) hmp->rx_skbuff[entry]->data;
- frame_status = le32_to_cpu(get_unaligned((__le32*)&(buf_addr[data_size - 12])));
+ frame_status = get_unaligned_le32(&(buf_addr[data_size - 12]));
if (hamachi_debug > 4)
printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n",
frame_status);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 1da55dd2a5a0..9d5721287d6f 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -148,13 +148,13 @@ static void sp_xmit_on_air(unsigned long channel)
if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->status2 = 0;
} else
mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
@@ -220,13 +220,13 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
*/
if (sp->duplex == 1) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, count);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
sp->xleft = count - actual;
sp->xhead = sp->xbuff + actual;
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
} else {
sp->xleft = count;
sp->xhead = sp->xbuff;
@@ -444,7 +444,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
}
if (sp->tx_enable) {
- actual = tty->driver->write(tty, sp->xhead, sp->xleft);
+ actual = tty->ops->write(tty, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
}
@@ -491,9 +491,7 @@ static void sixpack_receive_buf(struct tty_struct *tty,
sixpack_decode(sp, buf, count1);
sp_put(sp);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
/*
@@ -554,8 +552,8 @@ static void resync_tnc(unsigned long channel)
/* resync the TNC */
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
- sp->tty->driver->write(sp->tty, &resync_cmd, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &resync_cmd, 1);
/* Start resync timer again -- the TNC might be still absent */
@@ -573,7 +571,7 @@ static inline int tnc_init(struct sixpack *sp)
tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
- sp->tty->driver->write(sp->tty, &inbyte, 1);
+ sp->tty->ops->write(sp->tty, &inbyte, 1);
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
@@ -601,6 +599,8 @@ static int sixpack_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
if (!dev) {
@@ -914,9 +914,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
} else { /* output watchdog char if idle */
if ((sp->status2 != 0) && (sp->duplex == 1)) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
@@ -926,7 +926,7 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
}
/* needed to trigger the TNC watchdog */
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
/* if the state byte has been received, the TNC is present,
so the resync timer can be reset. */
@@ -956,12 +956,12 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd)
if ((sp->status & SIXP_RX_DCD_MASK) ==
SIXP_RX_DCD_MASK) {
sp->led_state = 0x68;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
}
} else {
sp->led_state = 0x60;
/* fill trailing bytes with zeroes */
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
rest = sp->rx_count;
if (rest != 0)
for (i = rest; i <= 3; i++)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 30c9b3b0d131..65166035aca0 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -516,7 +516,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
spin_unlock_bh(&ax->buflock);
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
- actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
+ actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
ax->stats.tx_packets++;
ax->stats.tx_bytes += actual;
@@ -546,7 +546,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
}
printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,
- (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ?
+ (ax->tty->ops->chars_in_buffer(ax->tty) || ax->xleft) ?
"bad line quality" : "driver error");
ax->xleft = 0;
@@ -736,6 +736,8 @@ static int mkiss_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
if (!dev) {
@@ -754,8 +756,7 @@ static int mkiss_open(struct tty_struct *tty)
tty->disc_data = ax;
tty->receive_room = 65535;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/* Restore default settings */
dev->type = ARPHRD_AX25;
@@ -935,9 +936,7 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
mkiss_put(ax);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
/*
@@ -962,7 +961,7 @@ static void mkiss_write_wakeup(struct tty_struct *tty)
goto out;
}
- actual = tty->driver->write(tty, ax->xhead, ax->xleft);
+ actual = tty->ops->write(tty, ax->xhead, ax->xleft);
ax->xleft -= actual;
ax->xhead += actual;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index ce4fc2ec2fe4..00527805e4f1 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1302,13 +1302,10 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
if (ibmveth_proc_dir) {
char u_addr[10];
sprintf(u_addr, "%x", adapter->vdev->unit_address);
- entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir);
- if (!entry) {
+ entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir,
+ &ibmveth_proc_fops, adapter);
+ if (!entry)
ibmveth_error_printk("Cannot create adapter proc entry");
- } else {
- entry->data = (void *) adapter;
- entry->proc_fops = &ibmveth_proc_fops;
- }
}
return;
}
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index fc753d7f674e..e6f40b7f9041 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -64,7 +64,7 @@ static int irtty_chars_in_buffer(struct sir_dev *dev)
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
- return priv->tty->driver->chars_in_buffer(priv->tty);
+ return tty_chars_in_buffer(priv->tty);
}
/* Wait (sleep) until underlaying hardware finished transmission
@@ -93,10 +93,8 @@ static void irtty_wait_until_sent(struct sir_dev *dev)
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
tty = priv->tty;
- if (tty->driver->wait_until_sent) {
- lock_kernel();
- tty->driver->wait_until_sent(tty, msecs_to_jiffies(100));
- unlock_kernel();
+ if (tty->ops->wait_until_sent) {
+ tty->ops->wait_until_sent(tty, msecs_to_jiffies(100));
}
else {
msleep(USBSERIAL_TX_DONE_DELAY);
@@ -125,48 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty;
- lock_kernel();
+ mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
-
- cflag &= ~CBAUD;
-
- IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
-
- switch (speed) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 38400:
- cflag |= B38400;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 9600:
- default:
- cflag |= B9600;
- break;
- }
-
- tty->termios->c_cflag = cflag;
- if (tty->driver->set_termios)
- tty->driver->set_termios(tty, &old_termios);
- unlock_kernel();
-
+ tty_encode_baud_rate(tty, speed, speed);
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old_termios);
priv->io.speed = speed;
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -202,8 +166,8 @@ static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
* This function is not yet defined for all tty driver, so
* let's be careful... Jean II
*/
- IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;);
- priv->tty->driver->tiocmset(priv->tty, NULL, set, clear);
+ IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;);
+ priv->tty->ops->tiocmset(priv->tty, NULL, set, clear);
return 0;
}
@@ -225,17 +189,13 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
tty = priv->tty;
- if (!tty->driver->write)
+ if (!tty->ops->write)
return 0;
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- if (tty->driver->write_room) {
- writelen = tty->driver->write_room(tty);
- if (writelen > len)
- writelen = len;
- }
- else
+ writelen = tty_write_room(tty);
+ if (writelen > len)
writelen = len;
- return tty->driver->write(tty, ptr, writelen);
+ return tty->ops->write(tty, ptr, writelen);
}
/* ------------------------------------------------------- */
@@ -321,7 +281,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
struct ktermios old_termios;
int cflag;
- lock_kernel();
+ mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
@@ -331,9 +291,9 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
cflag |= CREAD;
tty->termios->c_cflag = cflag;
- if (tty->driver->set_termios)
- tty->driver->set_termios(tty, &old_termios);
- unlock_kernel();
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old_termios);
+ mutex_unlock(&tty->termios_mutex);
}
/*****************************************************************/
@@ -359,8 +319,8 @@ static int irtty_start_dev(struct sir_dev *dev)
tty = priv->tty;
- if (tty->driver->start)
- tty->driver->start(tty);
+ if (tty->ops->start)
+ tty->ops->start(tty);
/* Make sure we can receive more data */
irtty_stop_receiver(tty, FALSE);
@@ -388,8 +348,8 @@ static int irtty_stop_dev(struct sir_dev *dev)
/* Make sure we don't receive more data */
irtty_stop_receiver(tty, TRUE);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
mutex_unlock(&irtty_mutex);
@@ -483,11 +443,10 @@ static int irtty_open(struct tty_struct *tty)
/* stop the underlying driver */
irtty_stop_receiver(tty, TRUE);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/* apply mtt override */
sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
@@ -564,8 +523,8 @@ static void irtty_close(struct tty_struct *tty)
/* Stop tty */
irtty_stop_receiver(tty, TRUE);
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
kfree(priv);
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 93916cf33f29..ad92d3ff1c40 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -464,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
}
fcs = ~(crc32_le(~0, buf, new_len));
- if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) {
+ if(fcs != get_unaligned_le32(buf + new_len)) {
IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
mcs->stats.rx_errors++;
mcs->stats.rx_crc_errors++;
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index a873d2b315ca..a7714da7c283 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -100,7 +100,9 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
+#ifdef CONFIG_PNP
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
+#endif
/* These are the known NSC chips */
static nsc_chip_t chips[] = {
@@ -156,9 +158,11 @@ static const struct pnp_device_id nsc_ircc_pnp_table[] = {
MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
static struct pnp_driver nsc_ircc_pnp_driver = {
+#ifdef CONFIG_PNP
.name = "nsc-ircc",
.id_table = nsc_ircc_pnp_table,
.probe = nsc_ircc_pnp_probe,
+#endif
};
/* Some prototypes */
@@ -916,6 +920,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
return 0;
}
+#ifdef CONFIG_PNP
/* PNP probing */
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
{
@@ -952,6 +957,7 @@ static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *i
return 0;
}
+#endif
/*
* Function nsc_ircc_setup (info)
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 1f26da761e9f..cfe0194fef71 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -376,6 +376,7 @@ MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
static int pnp_driver_registered;
+#ifdef CONFIG_PNP
static int __init smsc_ircc_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
{
@@ -402,7 +403,9 @@ static struct pnp_driver smsc_ircc_pnp_driver = {
.id_table = smsc_ircc_pnp_table,
.probe = smsc_ircc_pnp_probe,
};
-
+#else /* CONFIG_PNP */
+static struct pnp_driver smsc_ircc_pnp_driver;
+#endif
/*******************************************************************************
*
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index e59c485bc497..051963782749 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -329,7 +329,7 @@ static void fir_eof(struct stir_cb *stir)
}
fcs = ~(crc32_le(~0, rx_buff->data, len));
- if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) {
+ if (fcs != get_unaligned_le32(rx_buff->data + len)) {
pr_debug("crc error calc 0x%x len %d\n", fcs, len);
stir->stats.rx_errors++;
stir->stats.rx_crc_errors++;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index acd082a96a4f..d15e00b8591e 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1674,13 +1674,12 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (vlsi_proc_root != NULL) {
struct proc_dir_entry *ent;
- ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root);
+ ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO,
+ vlsi_proc_root, VLSI_PROC_FOPS, ndev);
if (!ent) {
IRDA_WARNING("%s: failed to create proc entry\n",
__FUNCTION__);
} else {
- ent->data = ndev;
- ent->proc_fops = VLSI_PROC_FOPS;
ent->size = 0;
}
idev->proc_entry = ent;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 2a66e5b7cebc..4ce8afd481c3 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -183,6 +183,9 @@ struct net_device * __init mac89x0_probe(int unit)
int err = -ENODEV;
DECLARE_MAC_BUF(mac);
+ if (!MACH_IS_MAC)
+ return ERR_PTR(-ENODEV);
+
dev = alloc_etherdev(sizeof(struct net_local));
if (!dev)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 18770527df99..51ad3765e075 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -781,6 +781,9 @@ static int __init mac_mace_init_module(void)
{
int err;
+ if (!MACH_IS_MAC)
+ return -ENODEV;
+
if ((err = platform_driver_register(&mac_mace_driver))) {
printk(KERN_ERR "Driver registration failed\n");
return err;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 2056cfc624dc..c36a03ae9bfb 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -450,7 +450,7 @@ static void macvlan_dellink(struct net_device *dev)
unregister_netdevice(dev);
if (list_empty(&port->vlans))
- macvlan_port_destroy(dev);
+ macvlan_port_destroy(port->dev);
}
static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 6fda0af9d0a6..95e87a2f8896 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -188,7 +188,8 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq,
EXPORT_SYMBOL_GPL(mlx4_cq_resize);
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
- struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq)
+ struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
+ int collapsed)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cq_table *cq_table = &priv->cq_table;
@@ -224,6 +225,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
cq_context = mailbox->buf;
memset(cq_context, 0, sizeof *cq_context);
+ cq_context->flags = cpu_to_be32(!!collapsed << 18);
cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
cq_context->comp_eqn = priv->eq_table.eq[MLX4_EQ_COMP].eqn;
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 79b317b88c86..03a9abcce524 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -551,7 +551,7 @@ int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages,
u64 mtt_seg;
int err = -ENOMEM;
- if (page_shift < 12 || page_shift >= 32)
+ if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32)
return -EINVAL;
/* All MTTs must fit in the same page */
@@ -607,15 +607,9 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_enable);
void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
u32 *lkey, u32 *rkey)
{
- u32 key;
-
if (!fmr->maps)
return;
- key = key_to_hw_index(fmr->mr.key);
- key &= dev->caps.num_mpts - 1;
- *lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
-
fmr->maps = 0;
*(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 381b36e5f64c..b7915cdcc6a5 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -91,6 +91,11 @@
*/
#define PHY_ADDR_REG 0x0000
#define SMI_REG 0x0004
+#define WINDOW_BASE(i) (0x0200 + ((i) << 3))
+#define WINDOW_SIZE(i) (0x0204 + ((i) << 3))
+#define WINDOW_REMAP_HIGH(i) (0x0280 + ((i) << 2))
+#define WINDOW_BAR_ENABLE 0x0290
+#define WINDOW_PROTECT(i) (0x0294 + ((i) << 4))
/*
* Per-port registers.
@@ -507,9 +512,23 @@ struct mv643xx_mib_counters {
u32 late_collision;
};
+struct mv643xx_shared_private {
+ void __iomem *eth_base;
+
+ /* used to protect SMI_REG, which is shared across ports */
+ spinlock_t phy_lock;
+
+ u32 win_protect;
+
+ unsigned int t_clk;
+};
+
struct mv643xx_private {
+ struct mv643xx_shared_private *shared;
int port_num; /* User Ethernet port number */
+ struct mv643xx_shared_private *shared_smi;
+
u32 rx_sram_addr; /* Base address of rx sram area */
u32 rx_sram_size; /* Size of rx sram area */
u32 tx_sram_addr; /* Base address of tx sram area */
@@ -614,19 +633,14 @@ static const struct ethtool_ops mv643xx_ethtool_ops;
static char mv643xx_driver_name[] = "mv643xx_eth";
static char mv643xx_driver_version[] = "1.0";
-static void __iomem *mv643xx_eth_base;
-
-/* used to protect SMI_REG, which is shared across ports */
-static DEFINE_SPINLOCK(mv643xx_eth_phy_lock);
-
static inline u32 rdl(struct mv643xx_private *mp, int offset)
{
- return readl(mv643xx_eth_base + offset);
+ return readl(mp->shared->eth_base + offset);
}
static inline void wrl(struct mv643xx_private *mp, int offset, u32 data)
{
- writel(data, mv643xx_eth_base + offset);
+ writel(data, mp->shared->eth_base + offset);
}
/*
@@ -1119,7 +1133,6 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
*
* INPUT:
* struct mv643xx_private *mp Ethernet port
- * unsigned int t_clk t_clk of the MV-643xx chip in HZ units
* unsigned int delay Delay in usec
*
* OUTPUT:
@@ -1130,10 +1143,10 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
*
*/
static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp,
- unsigned int t_clk, unsigned int delay)
+ unsigned int delay)
{
unsigned int port_num = mp->port_num;
- unsigned int coal = ((t_clk / 1000000) * delay) / 64;
+ unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
/* Set RX Coalescing mechanism */
wrl(mp, SDMA_CONFIG_REG(port_num),
@@ -1158,7 +1171,6 @@ static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp,
*
* INPUT:
* struct mv643xx_private *mp Ethernet port
- * unsigned int t_clk t_clk of the MV-643xx chip in HZ units
* unsigned int delay Delay in uSeconds
*
* OUTPUT:
@@ -1169,9 +1181,9 @@ static unsigned int eth_port_set_rx_coal(struct mv643xx_private *mp,
*
*/
static unsigned int eth_port_set_tx_coal(struct mv643xx_private *mp,
- unsigned int t_clk, unsigned int delay)
+ unsigned int delay)
{
- unsigned int coal = ((t_clk / 1000000) * delay) / 64;
+ unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
/* Set TX Coalescing mechanism */
wrl(mp, TX_FIFO_URGENT_THRESHOLD_REG(mp->port_num), coal << 4);
@@ -1413,11 +1425,11 @@ static int mv643xx_eth_open(struct net_device *dev)
#ifdef MV643XX_COAL
mp->rx_int_coal =
- eth_port_set_rx_coal(mp, 133000000, MV643XX_RX_COAL);
+ eth_port_set_rx_coal(mp, MV643XX_RX_COAL);
#endif
mp->tx_int_coal =
- eth_port_set_tx_coal(mp, 133000000, MV643XX_TX_COAL);
+ eth_port_set_tx_coal(mp, MV643XX_TX_COAL);
/* Unmask phy and link status changes interrupts */
wrl(mp, INTERRUPT_EXTEND_MASK_REG(port_num), ETH_INT_UNMASK_ALL_EXT);
@@ -1827,6 +1839,11 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (pd->shared == NULL) {
+ printk(KERN_ERR "No mv643xx_eth_platform_data->shared\n");
+ return -ENODEV;
+ }
+
dev = alloc_etherdev(sizeof(struct mv643xx_private));
if (!dev)
return -ENOMEM;
@@ -1877,8 +1894,16 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
spin_lock_init(&mp->lock);
+ mp->shared = platform_get_drvdata(pd->shared);
port_num = mp->port_num = pd->port_number;
+ if (mp->shared->win_protect)
+ wrl(mp, WINDOW_PROTECT(port_num), mp->shared->win_protect);
+
+ mp->shared_smi = mp->shared;
+ if (pd->shared_smi != NULL)
+ mp->shared_smi = platform_get_drvdata(pd->shared_smi);
+
/* set default config values */
eth_port_uc_addr_get(mp, dev->dev_addr);
mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
@@ -1983,30 +2008,91 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
return 0;
}
+static void mv643xx_eth_conf_mbus_windows(struct mv643xx_shared_private *msp,
+ struct mbus_dram_target_info *dram)
+{
+ void __iomem *base = msp->eth_base;
+ u32 win_enable;
+ u32 win_protect;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ writel(0, base + WINDOW_BASE(i));
+ writel(0, base + WINDOW_SIZE(i));
+ if (i < 4)
+ writel(0, base + WINDOW_REMAP_HIGH(i));
+ }
+
+ win_enable = 0x3f;
+ win_protect = 0;
+
+ for (i = 0; i < dram->num_cs; i++) {
+ struct mbus_dram_window *cs = dram->cs + i;
+
+ writel((cs->base & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ dram->mbus_dram_target_id, base + WINDOW_BASE(i));
+ writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i));
+
+ win_enable &= ~(1 << i);
+ win_protect |= 3 << (2 * i);
+ }
+
+ writel(win_enable, base + WINDOW_BAR_ENABLE);
+ msp->win_protect = win_protect;
+}
+
static int mv643xx_eth_shared_probe(struct platform_device *pdev)
{
static int mv643xx_version_printed = 0;
+ struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
+ struct mv643xx_shared_private *msp;
struct resource *res;
+ int ret;
if (!mv643xx_version_printed++)
printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n");
+ ret = -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
- return -ENODEV;
+ goto out;
- mv643xx_eth_base = ioremap(res->start, res->end - res->start + 1);
- if (mv643xx_eth_base == NULL)
- return -ENOMEM;
+ ret = -ENOMEM;
+ msp = kmalloc(sizeof(*msp), GFP_KERNEL);
+ if (msp == NULL)
+ goto out;
+ memset(msp, 0, sizeof(*msp));
+
+ msp->eth_base = ioremap(res->start, res->end - res->start + 1);
+ if (msp->eth_base == NULL)
+ goto out_free;
+
+ spin_lock_init(&msp->phy_lock);
+ msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000;
+
+ platform_set_drvdata(pdev, msp);
+
+ /*
+ * (Re-)program MBUS remapping windows if we are asked to.
+ */
+ if (pd != NULL && pd->dram != NULL)
+ mv643xx_eth_conf_mbus_windows(msp, pd->dram);
return 0;
+out_free:
+ kfree(msp);
+out:
+ return ret;
}
static int mv643xx_eth_shared_remove(struct platform_device *pdev)
{
- iounmap(mv643xx_eth_base);
- mv643xx_eth_base = NULL;
+ struct mv643xx_shared_private *msp = platform_get_drvdata(pdev);
+
+ iounmap(msp->eth_base);
+ kfree(msp);
return 0;
}
@@ -2906,15 +2992,16 @@ static void eth_port_reset(struct mv643xx_private *mp)
static void eth_port_read_smi_reg(struct mv643xx_private *mp,
unsigned int phy_reg, unsigned int *value)
{
+ void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG;
int phy_addr = ethernet_phy_get(mp);
unsigned long flags;
int i;
/* the SMI register is a shared resource */
- spin_lock_irqsave(&mv643xx_eth_phy_lock, flags);
+ spin_lock_irqsave(&mp->shared_smi->phy_lock, flags);
/* wait for the SMI register to become available */
- for (i = 0; rdl(mp, SMI_REG) & ETH_SMI_BUSY; i++) {
+ for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) {
if (i == PHY_WAIT_ITERATIONS) {
printk("%s: PHY busy timeout\n", mp->dev->name);
goto out;
@@ -2922,11 +3009,11 @@ static void eth_port_read_smi_reg(struct mv643xx_private *mp,
udelay(PHY_WAIT_MICRO_SECONDS);
}
- wrl(mp, SMI_REG,
- (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ);
+ writel((phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ,
+ smi_reg);
/* now wait for the data to be valid */
- for (i = 0; !(rdl(mp, SMI_REG) & ETH_SMI_READ_VALID); i++) {
+ for (i = 0; !(readl(smi_reg) & ETH_SMI_READ_VALID); i++) {
if (i == PHY_WAIT_ITERATIONS) {
printk("%s: PHY read timeout\n", mp->dev->name);
goto out;
@@ -2934,9 +3021,9 @@ static void eth_port_read_smi_reg(struct mv643xx_private *mp,
udelay(PHY_WAIT_MICRO_SECONDS);
}
- *value = rdl(mp, SMI_REG) & 0xffff;
+ *value = readl(smi_reg) & 0xffff;
out:
- spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags);
+ spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags);
}
/*
@@ -2962,17 +3049,16 @@ out:
static void eth_port_write_smi_reg(struct mv643xx_private *mp,
unsigned int phy_reg, unsigned int value)
{
- int phy_addr;
- int i;
+ void __iomem *smi_reg = mp->shared_smi->eth_base + SMI_REG;
+ int phy_addr = ethernet_phy_get(mp);
unsigned long flags;
-
- phy_addr = ethernet_phy_get(mp);
+ int i;
/* the SMI register is a shared resource */
- spin_lock_irqsave(&mv643xx_eth_phy_lock, flags);
+ spin_lock_irqsave(&mp->shared_smi->phy_lock, flags);
/* wait for the SMI register to become available */
- for (i = 0; rdl(mp, SMI_REG) & ETH_SMI_BUSY; i++) {
+ for (i = 0; readl(smi_reg) & ETH_SMI_BUSY; i++) {
if (i == PHY_WAIT_ITERATIONS) {
printk("%s: PHY busy timeout\n", mp->dev->name);
goto out;
@@ -2980,10 +3066,10 @@ static void eth_port_write_smi_reg(struct mv643xx_private *mp,
udelay(PHY_WAIT_MICRO_SECONDS);
}
- wrl(mp, SMI_REG, (phy_addr << 16) | (phy_reg << 21) |
- ETH_SMI_OPCODE_WRITE | (value & 0xffff));
+ writel((phy_addr << 16) | (phy_reg << 21) |
+ ETH_SMI_OPCODE_WRITE | (value & 0xffff), smi_reg);
out:
- spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags);
+ spin_unlock_irqrestore(&mp->shared_smi->phy_lock, flags);
}
/*
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index cead81e80f0c..c91b12ea26ad 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -144,11 +144,13 @@ struct myri10ge_tx_buf {
char *req_bytes;
struct myri10ge_tx_buffer_state *info;
int mask; /* number of transmit slots -1 */
- int boundary; /* boundary transmits cannot cross */
int req ____cacheline_aligned; /* transmit slots submitted */
int pkt_start; /* packets started */
+ int stop_queue;
+ int linearized;
int done ____cacheline_aligned; /* transmit slots completed */
int pkt_done; /* packets completed */
+ int wake_queue;
};
struct myri10ge_rx_done {
@@ -160,29 +162,50 @@ struct myri10ge_rx_done {
struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
};
-struct myri10ge_priv {
- int running; /* running? */
- int csum_flag; /* rx_csums? */
+struct myri10ge_slice_netstats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long rx_dropped;
+ unsigned long tx_dropped;
+};
+
+struct myri10ge_slice_state {
struct myri10ge_tx_buf tx; /* transmit ring */
struct myri10ge_rx_buf rx_small;
struct myri10ge_rx_buf rx_big;
struct myri10ge_rx_done rx_done;
+ struct net_device *dev;
+ struct napi_struct napi;
+ struct myri10ge_priv *mgp;
+ struct myri10ge_slice_netstats stats;
+ __be32 __iomem *irq_claim;
+ struct mcp_irq_data *fw_stats;
+ dma_addr_t fw_stats_bus;
+ int watchdog_tx_done;
+ int watchdog_tx_req;
+};
+
+struct myri10ge_priv {
+ struct myri10ge_slice_state ss;
+ int tx_boundary; /* boundary transmits cannot cross */
+ int running; /* running? */
+ int csum_flag; /* rx_csums? */
int small_bytes;
int big_bytes;
+ int max_intr_slots;
struct net_device *dev;
- struct napi_struct napi;
struct net_device_stats stats;
+ spinlock_t stats_lock;
u8 __iomem *sram;
int sram_size;
unsigned long board_span;
unsigned long iomem_base;
- __be32 __iomem *irq_claim;
__be32 __iomem *irq_deassert;
char *mac_addr_string;
struct mcp_cmd_response *cmd;
dma_addr_t cmd_bus;
- struct mcp_irq_data *fw_stats;
- dma_addr_t fw_stats_bus;
struct pci_dev *pdev;
int msi_enabled;
u32 link_state;
@@ -191,20 +214,16 @@ struct myri10ge_priv {
__be32 __iomem *intr_coal_delay_ptr;
int mtrr;
int wc_enabled;
- int wake_queue;
- int stop_queue;
int down_cnt;
wait_queue_head_t down_wq;
struct work_struct watchdog_work;
struct timer_list watchdog_timer;
- int watchdog_tx_done;
- int watchdog_tx_req;
- int watchdog_pause;
int watchdog_resets;
- int tx_linearized;
+ int watchdog_pause;
int pause;
char *fw_name;
char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
+ char *product_code_string;
char fw_version[128];
int fw_ver_major;
int fw_ver_minor;
@@ -228,58 +247,54 @@ static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";
static char *myri10ge_fw_name = NULL;
module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name\n");
+MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
static int myri10ge_ecrc_enable = 1;
module_param(myri10ge_ecrc_enable, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E\n");
-
-static int myri10ge_max_intr_slots = 1024;
-module_param(myri10ge_max_intr_slots, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_max_intr_slots, "Interrupt queue slots\n");
+MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E");
static int myri10ge_small_bytes = -1; /* -1 == auto */
module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n");
+MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets");
static int myri10ge_msi = 1; /* enable msi by default */
module_param(myri10ge_msi, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n");
+MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts");
static int myri10ge_intr_coal_delay = 75;
module_param(myri10ge_intr_coal_delay, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay\n");
+MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay");
static int myri10ge_flow_control = 1;
module_param(myri10ge_flow_control, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter\n");
+MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter");
static int myri10ge_deassert_wait = 1;
module_param(myri10ge_deassert_wait, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(myri10ge_deassert_wait,
- "Wait when deasserting legacy interrupts\n");
+ "Wait when deasserting legacy interrupts");
static int myri10ge_force_firmware = 0;
module_param(myri10ge_force_firmware, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_force_firmware,
- "Force firmware to assume aligned completions\n");
+ "Force firmware to assume aligned completions");
static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
module_param(myri10ge_initial_mtu, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");
+MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU");
static int myri10ge_napi_weight = 64;
module_param(myri10ge_napi_weight, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight\n");
+MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight");
static int myri10ge_watchdog_timeout = 1;
module_param(myri10ge_watchdog_timeout, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout\n");
+MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout");
static int myri10ge_max_irq_loops = 1048576;
module_param(myri10ge_max_irq_loops, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_max_irq_loops,
- "Set stuck legacy IRQ detection threshold\n");
+ "Set stuck legacy IRQ detection threshold");
#define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINK
@@ -289,21 +304,22 @@ MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
static int myri10ge_lro = 1;
module_param(myri10ge_lro, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n");
+MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload");
static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;
module_param(myri10ge_lro_max_pkts, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n");
+MODULE_PARM_DESC(myri10ge_lro_max_pkts,
+ "Number of LRO packets to be aggregated");
static int myri10ge_fill_thresh = 256;
module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
+MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed");
static int myri10ge_reset_recover = 1;
static int myri10ge_wcfifo = 0;
module_param(myri10ge_wcfifo, int, S_IRUGO);
-MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
+MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled");
#define MYRI10GE_FW_OFFSET 1024*1024
#define MYRI10GE_HIGHPART_TO_U32(X) \
@@ -359,8 +375,10 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
for (sleep_total = 0;
sleep_total < 1000
&& response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT);
- sleep_total += 10)
+ sleep_total += 10) {
udelay(10);
+ mb();
+ }
} else {
/* use msleep for most command */
for (sleep_total = 0;
@@ -420,6 +438,10 @@ static int myri10ge_read_mac_addr(struct myri10ge_priv *mgp)
ptr += 1;
}
}
+ if (memcmp(ptr, "PC=", 3) == 0) {
+ ptr += 3;
+ mgp->product_code_string = ptr;
+ }
if (memcmp((const void *)ptr, "SN=", 3) == 0) {
ptr += 3;
mgp->serial_number = simple_strtoul(ptr, &ptr, 10);
@@ -442,7 +464,7 @@ abort:
static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
{
char __iomem *submit;
- __be32 buf[16];
+ __be32 buf[16] __attribute__ ((__aligned__(8)));
u32 dma_low, dma_high;
int i;
@@ -609,13 +631,38 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
return status;
}
+int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_cmd cmd;
+ int status;
+
+ /* probe for IPv6 TSO support */
+ mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+ &cmd, 0);
+ if (status == 0) {
+ mgp->max_tso6 = cmd.data0;
+ mgp->features |= NETIF_F_TSO6;
+ }
+
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev,
+ "failed MXGEFW_CMD_GET_RX_RING_SIZE\n");
+ return -ENXIO;
+ }
+
+ mgp->max_intr_slots = 2 * (cmd.data0 / sizeof(struct mcp_dma_addr));
+
+ return 0;
+}
+
static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
{
char __iomem *submit;
- __be32 buf[16];
+ __be32 buf[16] __attribute__ ((__aligned__(8)));
u32 dma_low, dma_high, size;
int status, i;
- struct myri10ge_cmd cmd;
size = 0;
status = myri10ge_load_hotplug_firmware(mgp, &size);
@@ -635,7 +682,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
}
dev_info(&mgp->pdev->dev,
"Successfully adopted running firmware\n");
- if (mgp->tx.boundary == 4096) {
+ if (mgp->tx_boundary == 4096) {
dev_warn(&mgp->pdev->dev,
"Using firmware currently running on NIC"
". For optimal\n");
@@ -646,7 +693,9 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
}
mgp->fw_name = "adopted";
- mgp->tx.boundary = 2048;
+ mgp->tx_boundary = 2048;
+ myri10ge_dummy_rdma(mgp, 1);
+ status = myri10ge_get_firmware_capabilities(mgp);
return status;
}
@@ -681,26 +730,18 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
msleep(1);
mb();
i = 0;
- while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20) {
- msleep(1);
+ while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 9) {
+ msleep(1 << i);
i++;
}
if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) {
dev_err(&mgp->pdev->dev, "handoff failed\n");
return -ENXIO;
}
- dev_info(&mgp->pdev->dev, "handoff confirmed\n");
myri10ge_dummy_rdma(mgp, 1);
+ status = myri10ge_get_firmware_capabilities(mgp);
- /* probe for IPv6 TSO support */
- mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
- &cmd, 0);
- if (status == 0) {
- mgp->max_tso6 = cmd.data0;
- mgp->features |= NETIF_F_TSO6;
- }
- return 0;
+ return status;
}
static int myri10ge_update_mac_address(struct myri10ge_priv *mgp, u8 * addr)
@@ -772,7 +813,7 @@ static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type)
* transfers took to complete.
*/
- len = mgp->tx.boundary;
+ len = mgp->tx_boundary;
cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
@@ -834,17 +875,17 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
/* Now exchange information about interrupts */
- bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
- memset(mgp->rx_done.entry, 0, bytes);
+ bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
+ memset(mgp->ss.rx_done.entry, 0, bytes);
cmd.data0 = (u32) bytes;
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.rx_done.bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.rx_done.bus);
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0);
status |=
myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
- mgp->irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
+ mgp->ss.irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
&cmd, 0);
mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);
@@ -858,17 +899,17 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
}
put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
- memset(mgp->rx_done.entry, 0, bytes);
+ memset(mgp->ss.rx_done.entry, 0, bytes);
/* reset mcp/driver shared state back to 0 */
- mgp->tx.req = 0;
- mgp->tx.done = 0;
- mgp->tx.pkt_start = 0;
- mgp->tx.pkt_done = 0;
- mgp->rx_big.cnt = 0;
- mgp->rx_small.cnt = 0;
- mgp->rx_done.idx = 0;
- mgp->rx_done.cnt = 0;
+ mgp->ss.tx.req = 0;
+ mgp->ss.tx.done = 0;
+ mgp->ss.tx.pkt_start = 0;
+ mgp->ss.tx.pkt_done = 0;
+ mgp->ss.rx_big.cnt = 0;
+ mgp->ss.rx_small.cnt = 0;
+ mgp->ss.rx_done.idx = 0;
+ mgp->ss.rx_done.cnt = 0;
mgp->link_changes = 0;
status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
myri10ge_change_pause(mgp, mgp->pause);
@@ -1020,9 +1061,10 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev,
* page into an skb */
static inline int
-myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx,
int bytes, int len, __wsum csum)
{
+ struct myri10ge_priv *mgp = ss->mgp;
struct sk_buff *skb;
struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
int i, idx, hlen, remainder;
@@ -1052,11 +1094,10 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
rx_frags[0].page_offset += MXGEFW_PAD;
rx_frags[0].size -= MXGEFW_PAD;
len -= MXGEFW_PAD;
- lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags,
+ lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags,
len, len,
- /* opaque, will come back in get_frag_header */
- (void *)(__force unsigned long)csum,
- csum);
+ /* opaque, will come back in get_frag_header */
+ (void *)(__force unsigned long)csum, csum);
return 1;
}
@@ -1096,10 +1137,11 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
return 1;
}
-static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
+static inline void
+myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index)
{
- struct pci_dev *pdev = mgp->pdev;
- struct myri10ge_tx_buf *tx = &mgp->tx;
+ struct pci_dev *pdev = ss->mgp->pdev;
+ struct myri10ge_tx_buf *tx = &ss->tx;
struct sk_buff *skb;
int idx, len;
@@ -1117,8 +1159,8 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
len = pci_unmap_len(&tx->info[idx], len);
pci_unmap_len_set(&tx->info[idx], len, 0);
if (skb) {
- mgp->stats.tx_bytes += skb->len;
- mgp->stats.tx_packets++;
+ ss->stats.tx_bytes += skb->len;
+ ss->stats.tx_packets++;
dev_kfree_skb_irq(skb);
if (len)
pci_unmap_single(pdev,
@@ -1134,16 +1176,18 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
}
}
/* start the queue if we've stopped it */
- if (netif_queue_stopped(mgp->dev)
+ if (netif_queue_stopped(ss->dev)
&& tx->req - tx->done < (tx->mask >> 1)) {
- mgp->wake_queue++;
- netif_wake_queue(mgp->dev);
+ tx->wake_queue++;
+ netif_wake_queue(ss->dev);
}
}
-static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
+static inline int
+myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
{
- struct myri10ge_rx_done *rx_done = &mgp->rx_done;
+ struct myri10ge_rx_done *rx_done = &ss->rx_done;
+ struct myri10ge_priv *mgp = ss->mgp;
unsigned long rx_bytes = 0;
unsigned long rx_packets = 0;
unsigned long rx_ok;
@@ -1159,40 +1203,40 @@ static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
rx_done->entry[idx].length = 0;
checksum = csum_unfold(rx_done->entry[idx].checksum);
if (length <= mgp->small_bytes)
- rx_ok = myri10ge_rx_done(mgp, &mgp->rx_small,
+ rx_ok = myri10ge_rx_done(ss, &ss->rx_small,
mgp->small_bytes,
length, checksum);
else
- rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
+ rx_ok = myri10ge_rx_done(ss, &ss->rx_big,
mgp->big_bytes,
length, checksum);
rx_packets += rx_ok;
rx_bytes += rx_ok * (unsigned long)length;
cnt++;
- idx = cnt & (myri10ge_max_intr_slots - 1);
+ idx = cnt & (mgp->max_intr_slots - 1);
work_done++;
}
rx_done->idx = idx;
rx_done->cnt = cnt;
- mgp->stats.rx_packets += rx_packets;
- mgp->stats.rx_bytes += rx_bytes;
+ ss->stats.rx_packets += rx_packets;
+ ss->stats.rx_bytes += rx_bytes;
if (myri10ge_lro)
lro_flush_all(&rx_done->lro_mgr);
/* restock receive rings if needed */
- if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
- myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ if (ss->rx_small.fill_cnt - ss->rx_small.cnt < myri10ge_fill_thresh)
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
mgp->small_bytes + MXGEFW_PAD, 0);
- if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
- myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+ if (ss->rx_big.fill_cnt - ss->rx_big.cnt < myri10ge_fill_thresh)
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
return work_done;
}
static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
{
- struct mcp_irq_data *stats = mgp->fw_stats;
+ struct mcp_irq_data *stats = mgp->ss.fw_stats;
if (unlikely(stats->stats_updated)) {
unsigned link_up = ntohl(stats->link_up);
@@ -1219,9 +1263,9 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
}
}
if (mgp->rdma_tags_available !=
- ntohl(mgp->fw_stats->rdma_tags_available)) {
+ ntohl(stats->rdma_tags_available)) {
mgp->rdma_tags_available =
- ntohl(mgp->fw_stats->rdma_tags_available);
+ ntohl(stats->rdma_tags_available);
printk(KERN_WARNING "myri10ge: %s: RDMA timed out! "
"%d tags left\n", mgp->dev->name,
mgp->rdma_tags_available);
@@ -1234,26 +1278,27 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
static int myri10ge_poll(struct napi_struct *napi, int budget)
{
- struct myri10ge_priv *mgp =
- container_of(napi, struct myri10ge_priv, napi);
- struct net_device *netdev = mgp->dev;
+ struct myri10ge_slice_state *ss =
+ container_of(napi, struct myri10ge_slice_state, napi);
+ struct net_device *netdev = ss->mgp->dev;
int work_done;
/* process as many rx events as NAPI will allow */
- work_done = myri10ge_clean_rx_done(mgp, budget);
+ work_done = myri10ge_clean_rx_done(ss, budget);
if (work_done < budget) {
netif_rx_complete(netdev, napi);
- put_be32(htonl(3), mgp->irq_claim);
+ put_be32(htonl(3), ss->irq_claim);
}
return work_done;
}
static irqreturn_t myri10ge_intr(int irq, void *arg)
{
- struct myri10ge_priv *mgp = arg;
- struct mcp_irq_data *stats = mgp->fw_stats;
- struct myri10ge_tx_buf *tx = &mgp->tx;
+ struct myri10ge_slice_state *ss = arg;
+ struct myri10ge_priv *mgp = ss->mgp;
+ struct mcp_irq_data *stats = ss->fw_stats;
+ struct myri10ge_tx_buf *tx = &ss->tx;
u32 send_done_count;
int i;
@@ -1264,7 +1309,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
/* low bit indicates receives are present, so schedule
* napi poll handler */
if (stats->valid & 1)
- netif_rx_schedule(mgp->dev, &mgp->napi);
+ netif_rx_schedule(ss->dev, &ss->napi);
if (!mgp->msi_enabled) {
put_be32(0, mgp->irq_deassert);
@@ -1281,7 +1326,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
/* check for transmit completes and receives */
send_done_count = ntohl(stats->send_done_count);
if (send_done_count != tx->pkt_done)
- myri10ge_tx_done(mgp, (int)send_done_count);
+ myri10ge_tx_done(ss, (int)send_done_count);
if (unlikely(i > myri10ge_max_irq_loops)) {
printk(KERN_WARNING "myri10ge: %s: irq stuck?\n",
mgp->dev->name);
@@ -1296,16 +1341,46 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
myri10ge_check_statblock(mgp);
- put_be32(htonl(3), mgp->irq_claim + 1);
+ put_be32(htonl(3), ss->irq_claim + 1);
return (IRQ_HANDLED);
}
static int
myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ char *ptr;
+ int i;
+
cmd->autoneg = AUTONEG_DISABLE;
cmd->speed = SPEED_10000;
cmd->duplex = DUPLEX_FULL;
+
+ /*
+ * parse the product code to deterimine the interface type
+ * (CX4, XFP, Quad Ribbon Fiber) by looking at the character
+ * after the 3rd dash in the driver's cached copy of the
+ * EEPROM's product code string.
+ */
+ ptr = mgp->product_code_string;
+ if (ptr == NULL) {
+ printk(KERN_ERR "myri10ge: %s: Missing product code\n",
+ netdev->name);
+ return 0;
+ }
+ for (i = 0; i < 3; i++, ptr++) {
+ ptr = strchr(ptr, '-');
+ if (ptr == NULL) {
+ printk(KERN_ERR "myri10ge: %s: Invalid product "
+ "code %s\n", netdev->name,
+ mgp->product_code_string);
+ return 0;
+ }
+ }
+ if (*ptr == 'R' || *ptr == 'Q') {
+ /* We've found either an XFP or quad ribbon fiber */
+ cmd->port = PORT_FIBRE;
+ }
return 0;
}
@@ -1324,6 +1399,7 @@ static int
myri10ge_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coal)
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
+
coal->rx_coalesce_usecs = mgp->intr_coal_delay;
return 0;
}
@@ -1370,10 +1446,10 @@ myri10ge_get_ringparam(struct net_device *netdev,
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
- ring->rx_mini_max_pending = mgp->rx_small.mask + 1;
- ring->rx_max_pending = mgp->rx_big.mask + 1;
+ ring->rx_mini_max_pending = mgp->ss.rx_small.mask + 1;
+ ring->rx_max_pending = mgp->ss.rx_big.mask + 1;
ring->rx_jumbo_max_pending = 0;
- ring->tx_max_pending = mgp->rx_small.mask + 1;
+ ring->tx_max_pending = mgp->ss.rx_small.mask + 1;
ring->rx_mini_pending = ring->rx_mini_max_pending;
ring->rx_pending = ring->rx_max_pending;
ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
@@ -1383,6 +1459,7 @@ myri10ge_get_ringparam(struct net_device *netdev,
static u32 myri10ge_get_rx_csum(struct net_device *netdev)
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
+
if (mgp->csum_flag)
return 1;
else
@@ -1392,6 +1469,7 @@ static u32 myri10ge_get_rx_csum(struct net_device *netdev)
static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
+
if (csum_enabled)
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
else
@@ -1411,7 +1489,7 @@ static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
return 0;
}
-static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
+static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
"rx_length_errors", "rx_over_errors", "rx_crc_errors",
@@ -1421,28 +1499,39 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
/* device-specific stats */
"tx_boundary", "WC", "irq", "MSI",
"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
- "serial_number", "tx_pkt_start", "tx_pkt_done",
- "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
- "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
+ "serial_number", "watchdog_resets",
"link_changes", "link_up", "dropped_link_overflow",
"dropped_link_error_or_filtered",
"dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
"dropped_unicast_filtered", "dropped_multicast_filtered",
"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
- "dropped_no_big_buffer", "LRO aggregated", "LRO flushed",
+ "dropped_no_big_buffer"
+};
+
+static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = {
+ "----------- slice ---------",
+ "tx_pkt_start", "tx_pkt_done", "tx_req", "tx_done",
+ "rx_small_cnt", "rx_big_cnt",
+ "wake_queue", "stop_queue", "tx_linearized", "LRO aggregated",
+ "LRO flushed",
"LRO avg aggr", "LRO no_desc"
};
#define MYRI10GE_NET_STATS_LEN 21
-#define MYRI10GE_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_stats)
+#define MYRI10GE_MAIN_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_main_stats)
+#define MYRI10GE_SLICE_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_slice_stats)
static void
myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
{
switch (stringset) {
case ETH_SS_STATS:
- memcpy(data, *myri10ge_gstrings_stats,
- sizeof(myri10ge_gstrings_stats));
+ memcpy(data, *myri10ge_gstrings_main_stats,
+ sizeof(myri10ge_gstrings_main_stats));
+ data += sizeof(myri10ge_gstrings_main_stats);
+ memcpy(data, *myri10ge_gstrings_slice_stats,
+ sizeof(myri10ge_gstrings_slice_stats));
+ data += sizeof(myri10ge_gstrings_slice_stats);
break;
}
}
@@ -1451,7 +1540,7 @@ static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
- return MYRI10GE_STATS_LEN;
+ return MYRI10GE_MAIN_STATS_LEN + MYRI10GE_SLICE_STATS_LEN;
default:
return -EOPNOTSUPP;
}
@@ -1462,12 +1551,13 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 * data)
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
+ struct myri10ge_slice_state *ss;
int i;
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
data[i] = ((unsigned long *)&mgp->stats)[i];
- data[i++] = (unsigned int)mgp->tx.boundary;
+ data[i++] = (unsigned int)mgp->tx_boundary;
data[i++] = (unsigned int)mgp->wc_enabled;
data[i++] = (unsigned int)mgp->pdev->irq;
data[i++] = (unsigned int)mgp->msi_enabled;
@@ -1475,40 +1565,44 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
data[i++] = (unsigned int)mgp->write_dma;
data[i++] = (unsigned int)mgp->read_write_dma;
data[i++] = (unsigned int)mgp->serial_number;
- data[i++] = (unsigned int)mgp->tx.pkt_start;
- data[i++] = (unsigned int)mgp->tx.pkt_done;
- data[i++] = (unsigned int)mgp->tx.req;
- data[i++] = (unsigned int)mgp->tx.done;
- data[i++] = (unsigned int)mgp->rx_small.cnt;
- data[i++] = (unsigned int)mgp->rx_big.cnt;
- data[i++] = (unsigned int)mgp->wake_queue;
- data[i++] = (unsigned int)mgp->stop_queue;
data[i++] = (unsigned int)mgp->watchdog_resets;
- data[i++] = (unsigned int)mgp->tx_linearized;
data[i++] = (unsigned int)mgp->link_changes;
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
- data[i++] =
- (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_pause);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_phy);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_crc32);
+
+ /* firmware stats are useful only in the first slice */
+ ss = &mgp->ss;
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow);
data[i++] =
- (unsigned int)ntohl(mgp->fw_stats->dropped_unicast_filtered);
+ (unsigned int)ntohl(ss->fw_stats->dropped_link_error_or_filtered);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_pause);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_phy);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_crc32);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_unicast_filtered);
data[i++] =
- (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
- data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
- data[i++] = mgp->rx_done.lro_mgr.stats.aggregated;
- data[i++] = mgp->rx_done.lro_mgr.stats.flushed;
- if (mgp->rx_done.lro_mgr.stats.flushed)
- data[i++] = mgp->rx_done.lro_mgr.stats.aggregated /
- mgp->rx_done.lro_mgr.stats.flushed;
+ (unsigned int)ntohl(ss->fw_stats->dropped_multicast_filtered);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_runt);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_overrun);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer);
+ data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer);
+
+ data[i++] = 0;
+ data[i++] = (unsigned int)ss->tx.pkt_start;
+ data[i++] = (unsigned int)ss->tx.pkt_done;
+ data[i++] = (unsigned int)ss->tx.req;
+ data[i++] = (unsigned int)ss->tx.done;
+ data[i++] = (unsigned int)ss->rx_small.cnt;
+ data[i++] = (unsigned int)ss->rx_big.cnt;
+ data[i++] = (unsigned int)ss->tx.wake_queue;
+ data[i++] = (unsigned int)ss->tx.stop_queue;
+ data[i++] = (unsigned int)ss->tx.linearized;
+ data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
+ data[i++] = ss->rx_done.lro_mgr.stats.flushed;
+ if (ss->rx_done.lro_mgr.stats.flushed)
+ data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
+ ss->rx_done.lro_mgr.stats.flushed;
else
data[i++] = 0;
- data[i++] = mgp->rx_done.lro_mgr.stats.no_desc;
+ data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
}
static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1544,19 +1638,17 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_msglevel = myri10ge_get_msglevel
};
-static int myri10ge_allocate_rings(struct net_device *dev)
+static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
{
- struct myri10ge_priv *mgp;
+ struct myri10ge_priv *mgp = ss->mgp;
struct myri10ge_cmd cmd;
+ struct net_device *dev = mgp->dev;
int tx_ring_size, rx_ring_size;
int tx_ring_entries, rx_ring_entries;
int i, status;
size_t bytes;
- mgp = netdev_priv(dev);
-
/* get ring sizes */
-
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
tx_ring_size = cmd.data0;
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
@@ -1566,144 +1658,142 @@ static int myri10ge_allocate_rings(struct net_device *dev)
tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send);
rx_ring_entries = rx_ring_size / sizeof(struct mcp_dma_addr);
- mgp->tx.mask = tx_ring_entries - 1;
- mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1;
+ ss->tx.mask = tx_ring_entries - 1;
+ ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1;
status = -ENOMEM;
/* allocate the host shadow rings */
bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4)
- * sizeof(*mgp->tx.req_list);
- mgp->tx.req_bytes = kzalloc(bytes, GFP_KERNEL);
- if (mgp->tx.req_bytes == NULL)
+ * sizeof(*ss->tx.req_list);
+ ss->tx.req_bytes = kzalloc(bytes, GFP_KERNEL);
+ if (ss->tx.req_bytes == NULL)
goto abort_with_nothing;
/* ensure req_list entries are aligned to 8 bytes */
- mgp->tx.req_list = (struct mcp_kreq_ether_send *)
- ALIGN((unsigned long)mgp->tx.req_bytes, 8);
+ ss->tx.req_list = (struct mcp_kreq_ether_send *)
+ ALIGN((unsigned long)ss->tx.req_bytes, 8);
- bytes = rx_ring_entries * sizeof(*mgp->rx_small.shadow);
- mgp->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
- if (mgp->rx_small.shadow == NULL)
+ bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow);
+ ss->rx_small.shadow = kzalloc(bytes, GFP_KERNEL);
+ if (ss->rx_small.shadow == NULL)
goto abort_with_tx_req_bytes;
- bytes = rx_ring_entries * sizeof(*mgp->rx_big.shadow);
- mgp->rx_big.shadow = kzalloc(bytes, GFP_KERNEL);
- if (mgp->rx_big.shadow == NULL)
+ bytes = rx_ring_entries * sizeof(*ss->rx_big.shadow);
+ ss->rx_big.shadow = kzalloc(bytes, GFP_KERNEL);
+ if (ss->rx_big.shadow == NULL)
goto abort_with_rx_small_shadow;
/* allocate the host info rings */
- bytes = tx_ring_entries * sizeof(*mgp->tx.info);
- mgp->tx.info = kzalloc(bytes, GFP_KERNEL);
- if (mgp->tx.info == NULL)
+ bytes = tx_ring_entries * sizeof(*ss->tx.info);
+ ss->tx.info = kzalloc(bytes, GFP_KERNEL);
+ if (ss->tx.info == NULL)
goto abort_with_rx_big_shadow;
- bytes = rx_ring_entries * sizeof(*mgp->rx_small.info);
- mgp->rx_small.info = kzalloc(bytes, GFP_KERNEL);
- if (mgp->rx_small.info == NULL)
+ bytes = rx_ring_entries * sizeof(*ss->rx_small.info);
+ ss->rx_small.info = kzalloc(bytes, GFP_KERNEL);
+ if (ss->rx_small.info == NULL)
goto abort_with_tx_info;
- bytes = rx_ring_entries * sizeof(*mgp->rx_big.info);
- mgp->rx_big.info = kzalloc(bytes, GFP_KERNEL);
- if (mgp->rx_big.info == NULL)
+ bytes = rx_ring_entries * sizeof(*ss->rx_big.info);
+ ss->rx_big.info = kzalloc(bytes, GFP_KERNEL);
+ if (ss->rx_big.info == NULL)
goto abort_with_rx_small_info;
/* Fill the receive rings */
- mgp->rx_big.cnt = 0;
- mgp->rx_small.cnt = 0;
- mgp->rx_big.fill_cnt = 0;
- mgp->rx_small.fill_cnt = 0;
- mgp->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
- mgp->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
- mgp->rx_small.watchdog_needed = 0;
- mgp->rx_big.watchdog_needed = 0;
- myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ ss->rx_big.cnt = 0;
+ ss->rx_small.cnt = 0;
+ ss->rx_big.fill_cnt = 0;
+ ss->rx_small.fill_cnt = 0;
+ ss->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
+ ss->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
+ ss->rx_small.watchdog_needed = 0;
+ ss->rx_big.watchdog_needed = 0;
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
mgp->small_bytes + MXGEFW_PAD, 0);
- if (mgp->rx_small.fill_cnt < mgp->rx_small.mask + 1) {
+ if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) {
printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
- dev->name, mgp->rx_small.fill_cnt);
+ dev->name, ss->rx_small.fill_cnt);
goto abort_with_rx_small_ring;
}
- myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
- if (mgp->rx_big.fill_cnt < mgp->rx_big.mask + 1) {
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
+ if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) {
printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
- dev->name, mgp->rx_big.fill_cnt);
+ dev->name, ss->rx_big.fill_cnt);
goto abort_with_rx_big_ring;
}
return 0;
abort_with_rx_big_ring:
- for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
- int idx = i & mgp->rx_big.mask;
- myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+ for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) {
+ int idx = i & ss->rx_big.mask;
+ myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_big.info[idx],
mgp->big_bytes);
- put_page(mgp->rx_big.info[idx].page);
+ put_page(ss->rx_big.info[idx].page);
}
abort_with_rx_small_ring:
- for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
- int idx = i & mgp->rx_small.mask;
- myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+ for (i = ss->rx_small.cnt; i < ss->rx_small.fill_cnt; i++) {
+ int idx = i & ss->rx_small.mask;
+ myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_small.info[idx],
mgp->small_bytes + MXGEFW_PAD);
- put_page(mgp->rx_small.info[idx].page);
+ put_page(ss->rx_small.info[idx].page);
}
- kfree(mgp->rx_big.info);
+ kfree(ss->rx_big.info);
abort_with_rx_small_info:
- kfree(mgp->rx_small.info);
+ kfree(ss->rx_small.info);
abort_with_tx_info:
- kfree(mgp->tx.info);
+ kfree(ss->tx.info);
abort_with_rx_big_shadow:
- kfree(mgp->rx_big.shadow);
+ kfree(ss->rx_big.shadow);
abort_with_rx_small_shadow:
- kfree(mgp->rx_small.shadow);
+ kfree(ss->rx_small.shadow);
abort_with_tx_req_bytes:
- kfree(mgp->tx.req_bytes);
- mgp->tx.req_bytes = NULL;
- mgp->tx.req_list = NULL;
+ kfree(ss->tx.req_bytes);
+ ss->tx.req_bytes = NULL;
+ ss->tx.req_list = NULL;
abort_with_nothing:
return status;
}
-static void myri10ge_free_rings(struct net_device *dev)
+static void myri10ge_free_rings(struct myri10ge_slice_state *ss)
{
- struct myri10ge_priv *mgp;
+ struct myri10ge_priv *mgp = ss->mgp;
struct sk_buff *skb;
struct myri10ge_tx_buf *tx;
int i, len, idx;
- mgp = netdev_priv(dev);
-
- for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
- idx = i & mgp->rx_big.mask;
- if (i == mgp->rx_big.fill_cnt - 1)
- mgp->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
- myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+ for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) {
+ idx = i & ss->rx_big.mask;
+ if (i == ss->rx_big.fill_cnt - 1)
+ ss->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
+ myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_big.info[idx],
mgp->big_bytes);
- put_page(mgp->rx_big.info[idx].page);
+ put_page(ss->rx_big.info[idx].page);
}
- for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
- idx = i & mgp->rx_small.mask;
- if (i == mgp->rx_small.fill_cnt - 1)
- mgp->rx_small.info[idx].page_offset =
+ for (i = ss->rx_small.cnt; i < ss->rx_small.fill_cnt; i++) {
+ idx = i & ss->rx_small.mask;
+ if (i == ss->rx_small.fill_cnt - 1)
+ ss->rx_small.info[idx].page_offset =
MYRI10GE_ALLOC_SIZE;
- myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+ myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_small.info[idx],
mgp->small_bytes + MXGEFW_PAD);
- put_page(mgp->rx_small.info[idx].page);
+ put_page(ss->rx_small.info[idx].page);
}
- tx = &mgp->tx;
+ tx = &ss->tx;
while (tx->done != tx->req) {
idx = tx->done & tx->mask;
skb = tx->info[idx].skb;
@@ -1714,7 +1804,7 @@ static void myri10ge_free_rings(struct net_device *dev)
len = pci_unmap_len(&tx->info[idx], len);
pci_unmap_len_set(&tx->info[idx], len, 0);
if (skb) {
- mgp->stats.tx_dropped++;
+ ss->stats.tx_dropped++;
dev_kfree_skb_any(skb);
if (len)
pci_unmap_single(mgp->pdev,
@@ -1729,19 +1819,19 @@ static void myri10ge_free_rings(struct net_device *dev)
PCI_DMA_TODEVICE);
}
}
- kfree(mgp->rx_big.info);
+ kfree(ss->rx_big.info);
- kfree(mgp->rx_small.info);
+ kfree(ss->rx_small.info);
- kfree(mgp->tx.info);
+ kfree(ss->tx.info);
- kfree(mgp->rx_big.shadow);
+ kfree(ss->rx_big.shadow);
- kfree(mgp->rx_small.shadow);
+ kfree(ss->rx_small.shadow);
- kfree(mgp->tx.req_bytes);
- mgp->tx.req_bytes = NULL;
- mgp->tx.req_list = NULL;
+ kfree(ss->tx.req_bytes);
+ ss->tx.req_bytes = NULL;
+ ss->tx.req_list = NULL;
}
static int myri10ge_request_irq(struct myri10ge_priv *mgp)
@@ -1840,13 +1930,11 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
static int myri10ge_open(struct net_device *dev)
{
- struct myri10ge_priv *mgp;
+ struct myri10ge_priv *mgp = netdev_priv(dev);
struct myri10ge_cmd cmd;
struct net_lro_mgr *lro_mgr;
int status, big_pow2;
- mgp = netdev_priv(dev);
-
if (mgp->running != MYRI10GE_ETH_STOPPED)
return -EBUSY;
@@ -1883,16 +1971,16 @@ static int myri10ge_open(struct net_device *dev)
/* get the lanai pointers to the send and receive rings */
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
- mgp->tx.lanai =
+ mgp->ss.tx.lanai =
(struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0);
status |=
myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0);
- mgp->rx_small.lanai =
+ mgp->ss.rx_small.lanai =
(struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
- mgp->rx_big.lanai =
+ mgp->ss.rx_big.lanai =
(struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
if (status != 0) {
@@ -1904,15 +1992,15 @@ static int myri10ge_open(struct net_device *dev)
}
if (myri10ge_wcfifo && mgp->wc_enabled) {
- mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
- mgp->rx_small.wc_fifo =
+ mgp->ss.tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
+ mgp->ss.rx_small.wc_fifo =
(u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
- mgp->rx_big.wc_fifo =
+ mgp->ss.rx_big.wc_fifo =
(u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
} else {
- mgp->tx.wc_fifo = NULL;
- mgp->rx_small.wc_fifo = NULL;
- mgp->rx_big.wc_fifo = NULL;
+ mgp->ss.tx.wc_fifo = NULL;
+ mgp->ss.rx_small.wc_fifo = NULL;
+ mgp->ss.rx_big.wc_fifo = NULL;
}
/* Firmware needs the big buff size as a power of 2. Lie and
@@ -1929,7 +2017,7 @@ static int myri10ge_open(struct net_device *dev)
mgp->big_bytes = big_pow2;
}
- status = myri10ge_allocate_rings(dev);
+ status = myri10ge_allocate_rings(&mgp->ss);
if (status != 0)
goto abort_with_irq;
@@ -1948,12 +2036,12 @@ static int myri10ge_open(struct net_device *dev)
goto abort_with_rings;
}
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.fw_stats_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.fw_stats_bus);
cmd.data2 = sizeof(struct mcp_irq_data);
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
if (status == -ENOSYS) {
- dma_addr_t bus = mgp->fw_stats_bus;
+ dma_addr_t bus = mgp->ss.fw_stats_bus;
bus += offsetof(struct mcp_irq_data, send_done_count);
cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
@@ -1974,20 +2062,20 @@ static int myri10ge_open(struct net_device *dev)
mgp->link_state = ~0U;
mgp->rdma_tags_available = 15;
- lro_mgr = &mgp->rx_done.lro_mgr;
+ lro_mgr = &mgp->ss.rx_done.lro_mgr;
lro_mgr->dev = dev;
lro_mgr->features = LRO_F_NAPI;
lro_mgr->ip_summed = CHECKSUM_COMPLETE;
lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
- lro_mgr->lro_arr = mgp->rx_done.lro_desc;
+ lro_mgr->lro_arr = mgp->ss.rx_done.lro_desc;
lro_mgr->get_frag_header = myri10ge_get_frag_header;
lro_mgr->max_aggr = myri10ge_lro_max_pkts;
lro_mgr->frag_align_pad = 2;
if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
lro_mgr->max_aggr = MAX_SKB_FRAGS;
- napi_enable(&mgp->napi); /* must happen prior to any irq */
+ napi_enable(&mgp->ss.napi); /* must happen prior to any irq */
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
if (status) {
@@ -1996,8 +2084,8 @@ static int myri10ge_open(struct net_device *dev)
goto abort_with_rings;
}
- mgp->wake_queue = 0;
- mgp->stop_queue = 0;
+ mgp->ss.tx.wake_queue = 0;
+ mgp->ss.tx.stop_queue = 0;
mgp->running = MYRI10GE_ETH_RUNNING;
mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
add_timer(&mgp->watchdog_timer);
@@ -2005,7 +2093,7 @@ static int myri10ge_open(struct net_device *dev)
return 0;
abort_with_rings:
- myri10ge_free_rings(dev);
+ myri10ge_free_rings(&mgp->ss);
abort_with_irq:
myri10ge_free_irq(mgp);
@@ -2017,21 +2105,19 @@ abort_with_nothing:
static int myri10ge_close(struct net_device *dev)
{
- struct myri10ge_priv *mgp;
+ struct myri10ge_priv *mgp = netdev_priv(dev);
struct myri10ge_cmd cmd;
int status, old_down_cnt;
- mgp = netdev_priv(dev);
-
if (mgp->running != MYRI10GE_ETH_RUNNING)
return 0;
- if (mgp->tx.req_bytes == NULL)
+ if (mgp->ss.tx.req_bytes == NULL)
return 0;
del_timer_sync(&mgp->watchdog_timer);
mgp->running = MYRI10GE_ETH_STOPPING;
- napi_disable(&mgp->napi);
+ napi_disable(&mgp->ss.napi);
netif_carrier_off(dev);
netif_stop_queue(dev);
old_down_cnt = mgp->down_cnt;
@@ -2047,7 +2133,7 @@ static int myri10ge_close(struct net_device *dev)
netif_tx_disable(dev);
myri10ge_free_irq(mgp);
- myri10ge_free_rings(dev);
+ myri10ge_free_rings(&mgp->ss);
mgp->running = MYRI10GE_ETH_STOPPED;
return 0;
@@ -2143,7 +2229,7 @@ myri10ge_submit_req_wc(struct myri10ge_tx_buf *tx,
/*
* Transmit a packet. We need to split the packet so that a single
- * segment does not cross myri10ge->tx.boundary, so this makes segment
+ * segment does not cross myri10ge->tx_boundary, so this makes segment
* counting tricky. So rather than try to count segments up front, we
* just give up if there are too few segments to hold a reasonably
* fragmented packet currently available. If we run
@@ -2154,8 +2240,9 @@ myri10ge_submit_req_wc(struct myri10ge_tx_buf *tx,
static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct myri10ge_priv *mgp = netdev_priv(dev);
+ struct myri10ge_slice_state *ss;
struct mcp_kreq_ether_send *req;
- struct myri10ge_tx_buf *tx = &mgp->tx;
+ struct myri10ge_tx_buf *tx;
struct skb_frag_struct *frag;
dma_addr_t bus;
u32 low;
@@ -2166,6 +2253,9 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev)
int cum_len, seglen, boundary, rdma_count;
u8 flags, odd_flag;
+ /* always transmit through slot 0 */
+ ss = &mgp->ss;
+ tx = &ss->tx;
again:
req = tx->req_list;
avail = tx->mask - 1 - (tx->req - tx->done);
@@ -2180,7 +2270,7 @@ again:
if ((unlikely(avail < max_segments))) {
/* we are out of transmit resources */
- mgp->stop_queue++;
+ tx->stop_queue++;
netif_stop_queue(dev);
return 1;
}
@@ -2242,7 +2332,7 @@ again:
if (skb_padto(skb, ETH_ZLEN)) {
/* The packet is gone, so we must
* return 0 */
- mgp->stats.tx_dropped += 1;
+ ss->stats.tx_dropped += 1;
return 0;
}
/* adjust the len to account for the zero pad
@@ -2284,7 +2374,7 @@ again:
while (1) {
/* Break the SKB or Fragment up into pieces which
- * do not cross mgp->tx.boundary */
+ * do not cross mgp->tx_boundary */
low = MYRI10GE_LOWPART_TO_U32(bus);
high_swapped = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
while (len) {
@@ -2294,7 +2384,8 @@ again:
if (unlikely(count == max_segments))
goto abort_linearize;
- boundary = (low + tx->boundary) & ~(tx->boundary - 1);
+ boundary =
+ (low + mgp->tx_boundary) & ~(mgp->tx_boundary - 1);
seglen = boundary - low;
if (seglen > len)
seglen = len;
@@ -2378,7 +2469,7 @@ again:
myri10ge_submit_req_wc(tx, tx->req_list, count);
tx->pkt_start++;
if ((avail - count) < MXGEFW_MAX_SEND_DESC) {
- mgp->stop_queue++;
+ tx->stop_queue++;
netif_stop_queue(dev);
}
dev->trans_start = jiffies;
@@ -2420,12 +2511,12 @@ abort_linearize:
if (skb_linearize(skb))
goto drop;
- mgp->tx_linearized++;
+ tx->linearized++;
goto again;
drop:
dev_kfree_skb_any(skb);
- mgp->stats.tx_dropped += 1;
+ ss->stats.tx_dropped += 1;
return 0;
}
@@ -2433,11 +2524,11 @@ drop:
static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff *segs, *curr;
- struct myri10ge_priv *mgp = dev->priv;
+ struct myri10ge_priv *mgp = netdev_priv(dev);
int status;
segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
goto drop;
while (segs) {
@@ -2473,14 +2564,13 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
static void myri10ge_set_multicast_list(struct net_device *dev)
{
+ struct myri10ge_priv *mgp = netdev_priv(dev);
struct myri10ge_cmd cmd;
- struct myri10ge_priv *mgp;
struct dev_mc_list *mc_list;
__be32 data[2] = { 0, 0 };
int err;
DECLARE_MAC_BUF(mac);
- mgp = netdev_priv(dev);
/* can be called from atomic contexts,
* pass 1 to force atomicity in myri10ge_send_cmd() */
myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
@@ -2616,13 +2706,14 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
if (ext_type != PCI_EXP_TYPE_ROOT_PORT) {
if (myri10ge_ecrc_enable > 1) {
- struct pci_dev *old_bridge = bridge;
+ struct pci_dev *prev_bridge, *old_bridge = bridge;
/* Walk the hierarchy up to the root port
* where ECRC has to be enabled */
do {
+ prev_bridge = bridge;
bridge = bridge->bus->self;
- if (!bridge) {
+ if (!bridge || prev_bridge == bridge) {
dev_err(dev,
"Failed to find root port"
" to force ECRC\n");
@@ -2681,9 +2772,9 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
* already been enabled, then it must use a firmware image which works
* around unaligned completion packets (myri10ge_ethp_z8e.dat), and it
* should also ensure that it never gives the device a Read-DMA which is
- * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is
+ * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is
* enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat)
- * firmware image, and set tx.boundary to 4KB.
+ * firmware image, and set tx_boundary to 4KB.
*/
static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
@@ -2692,7 +2783,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
struct device *dev = &pdev->dev;
int status;
- mgp->tx.boundary = 4096;
+ mgp->tx_boundary = 4096;
/*
* Verify the max read request size was set to 4KB
* before trying the test with 4KB.
@@ -2704,7 +2795,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
}
if (status != 4096) {
dev_warn(dev, "Max Read Request size != 4096 (%d)\n", status);
- mgp->tx.boundary = 2048;
+ mgp->tx_boundary = 2048;
}
/*
* load the optimized firmware (which assumes aligned PCIe
@@ -2737,7 +2828,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
"Please install up to date fw\n");
abort:
/* fall back to using the unaligned firmware */
- mgp->tx.boundary = 2048;
+ mgp->tx_boundary = 2048;
mgp->fw_name = myri10ge_fw_unaligned;
}
@@ -2758,7 +2849,7 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
if (link_width < 8) {
dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
link_width);
- mgp->tx.boundary = 4096;
+ mgp->tx_boundary = 4096;
mgp->fw_name = myri10ge_fw_aligned;
} else {
myri10ge_firmware_probe(mgp);
@@ -2767,12 +2858,12 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
if (myri10ge_force_firmware == 1) {
dev_info(&mgp->pdev->dev,
"Assuming aligned completions (forced)\n");
- mgp->tx.boundary = 4096;
+ mgp->tx_boundary = 4096;
mgp->fw_name = myri10ge_fw_aligned;
} else {
dev_info(&mgp->pdev->dev,
"Assuming unaligned completions (forced)\n");
- mgp->tx.boundary = 2048;
+ mgp->tx_boundary = 2048;
mgp->fw_name = myri10ge_fw_unaligned;
}
}
@@ -2889,6 +2980,7 @@ static void myri10ge_watchdog(struct work_struct *work)
{
struct myri10ge_priv *mgp =
container_of(work, struct myri10ge_priv, watchdog_work);
+ struct myri10ge_tx_buf *tx;
u32 reboot;
int status;
u16 cmd, vendor;
@@ -2938,15 +3030,16 @@ static void myri10ge_watchdog(struct work_struct *work)
printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n",
mgp->dev->name);
+ tx = &mgp->ss.tx;
printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
- mgp->dev->name, mgp->tx.req, mgp->tx.done,
- mgp->tx.pkt_start, mgp->tx.pkt_done,
- (int)ntohl(mgp->fw_stats->send_done_count));
+ mgp->dev->name, tx->req, tx->done,
+ tx->pkt_start, tx->pkt_done,
+ (int)ntohl(mgp->ss.fw_stats->send_done_count));
msleep(2000);
printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
- mgp->dev->name, mgp->tx.req, mgp->tx.done,
- mgp->tx.pkt_start, mgp->tx.pkt_done,
- (int)ntohl(mgp->fw_stats->send_done_count));
+ mgp->dev->name, tx->req, tx->done,
+ tx->pkt_start, tx->pkt_done,
+ (int)ntohl(mgp->ss.fw_stats->send_done_count));
}
rtnl_lock();
myri10ge_close(mgp->dev);
@@ -2969,28 +3062,31 @@ static void myri10ge_watchdog(struct work_struct *work)
static void myri10ge_watchdog_timer(unsigned long arg)
{
struct myri10ge_priv *mgp;
+ struct myri10ge_slice_state *ss;
u32 rx_pause_cnt;
mgp = (struct myri10ge_priv *)arg;
- if (mgp->rx_small.watchdog_needed) {
- myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+ rx_pause_cnt = ntohl(mgp->ss.fw_stats->dropped_pause);
+
+ ss = &mgp->ss;
+ if (ss->rx_small.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
mgp->small_bytes + MXGEFW_PAD, 1);
- if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt >=
+ if (ss->rx_small.fill_cnt - ss->rx_small.cnt >=
myri10ge_fill_thresh)
- mgp->rx_small.watchdog_needed = 0;
+ ss->rx_small.watchdog_needed = 0;
}
- if (mgp->rx_big.watchdog_needed) {
- myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 1);
- if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt >=
+ if (ss->rx_big.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 1);
+ if (ss->rx_big.fill_cnt - ss->rx_big.cnt >=
myri10ge_fill_thresh)
- mgp->rx_big.watchdog_needed = 0;
+ ss->rx_big.watchdog_needed = 0;
}
- rx_pause_cnt = ntohl(mgp->fw_stats->dropped_pause);
- if (mgp->tx.req != mgp->tx.done &&
- mgp->tx.done == mgp->watchdog_tx_done &&
- mgp->watchdog_tx_req != mgp->watchdog_tx_done) {
+ if (ss->tx.req != ss->tx.done &&
+ ss->tx.done == ss->watchdog_tx_done &&
+ ss->watchdog_tx_req != ss->watchdog_tx_done) {
/* nic seems like it might be stuck.. */
if (rx_pause_cnt != mgp->watchdog_pause) {
if (net_ratelimit())
@@ -3005,8 +3101,8 @@ static void myri10ge_watchdog_timer(unsigned long arg)
/* rearm timer */
mod_timer(&mgp->watchdog_timer,
jiffies + myri10ge_watchdog_timeout * HZ);
- mgp->watchdog_tx_done = mgp->tx.done;
- mgp->watchdog_tx_req = mgp->tx.req;
+ ss->watchdog_tx_done = ss->tx.done;
+ ss->watchdog_tx_req = ss->tx.req;
mgp->watchdog_pause = rx_pause_cnt;
}
@@ -3030,7 +3126,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mgp = netdev_priv(netdev);
mgp->dev = netdev;
- netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight);
+ netif_napi_add(netdev, &mgp->ss.napi, myri10ge_poll, myri10ge_napi_weight);
mgp->pdev = pdev;
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
@@ -3076,9 +3172,9 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (mgp->cmd == NULL)
goto abort_with_netdev;
- mgp->fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
- &mgp->fw_stats_bus, GFP_KERNEL);
- if (mgp->fw_stats == NULL)
+ mgp->ss.fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
+ &mgp->ss.fw_stats_bus, GFP_KERNEL);
+ if (mgp->ss.fw_stats == NULL)
goto abort_with_cmd;
mgp->board_span = pci_resource_len(pdev, 0);
@@ -3118,12 +3214,12 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->dev_addr[i] = mgp->mac_addr[i];
/* allocate rx done ring */
- bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
- mgp->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
- &mgp->rx_done.bus, GFP_KERNEL);
- if (mgp->rx_done.entry == NULL)
+ bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
+ mgp->ss.rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
+ &mgp->ss.rx_done.bus, GFP_KERNEL);
+ if (mgp->ss.rx_done.entry == NULL)
goto abort_with_ioremap;
- memset(mgp->rx_done.entry, 0, bytes);
+ memset(mgp->ss.rx_done.entry, 0, bytes);
myri10ge_select_firmware(mgp);
@@ -3183,7 +3279,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
(mgp->msi_enabled ? "MSI" : "xPIC"),
- netdev->irq, mgp->tx.boundary, mgp->fw_name,
+ netdev->irq, mgp->tx_boundary, mgp->fw_name,
(mgp->wc_enabled ? "Enabled" : "Disabled"));
return 0;
@@ -3195,9 +3291,9 @@ abort_with_firmware:
myri10ge_dummy_rdma(mgp, 0);
abort_with_rx_done:
- bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+ bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
dma_free_coherent(&pdev->dev, bytes,
- mgp->rx_done.entry, mgp->rx_done.bus);
+ mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
abort_with_ioremap:
iounmap(mgp->sram);
@@ -3207,8 +3303,8 @@ abort_with_wc:
if (mgp->mtrr >= 0)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
- dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
- mgp->fw_stats, mgp->fw_stats_bus);
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
+ mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
abort_with_cmd:
dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
@@ -3246,9 +3342,9 @@ static void myri10ge_remove(struct pci_dev *pdev)
/* avoid a memory leak */
pci_restore_state(pdev);
- bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
+ bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
dma_free_coherent(&pdev->dev, bytes,
- mgp->rx_done.entry, mgp->rx_done.bus);
+ mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
iounmap(mgp->sram);
@@ -3256,8 +3352,8 @@ static void myri10ge_remove(struct pci_dev *pdev)
if (mgp->mtrr >= 0)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
- dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
- mgp->fw_stats, mgp->fw_stats_bus);
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
+ mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
mgp->cmd, mgp->cmd_bus);
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 58e57178c563..fdbeeee07372 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -10,7 +10,7 @@ struct mcp_dma_addr {
__be32 low;
};
-/* 4 Bytes. 8 Bytes for NDIS drivers. */
+/* 4 Bytes */
struct mcp_slot {
__sum16 checksum;
__be16 length;
@@ -144,6 +144,7 @@ enum myri10ge_mcp_cmd_type {
* a power of 2 number of entries. */
MXGEFW_CMD_SET_INTRQ_SIZE, /* in bytes */
+#define MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK (1 << 31)
/* command to bring ethernet interface up. Above parameters
* (plus mtu & mac address) must have been exchanged prior
@@ -221,10 +222,14 @@ enum myri10ge_mcp_cmd_type {
MXGEFW_CMD_GET_MAX_RSS_QUEUES,
MXGEFW_CMD_ENABLE_RSS_QUEUES,
/* data0 = number of slices n (0, 1, ..., n-1) to enable
- * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue.
+ * data1 = interrupt mode.
+ * 0=share one INTx/MSI, 1=use one MSI-X per queue.
* If all queues share one interrupt, the driver must have set
* RSS_SHARED_INTERRUPT_DMA before enabling queues.
*/
+#define MXGEFW_SLICE_INTR_MODE_SHARED 0
+#define MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE 1
+
MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET,
MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA,
/* data0, data1 = bus address lsw, msw */
@@ -241,10 +246,14 @@ enum myri10ge_mcp_cmd_type {
* 0: disable rss. nic does not distribute receive packets.
* 1: enable rss. nic distributes receive packets among queues.
* data1 = hash type
- * 1: IPV4
- * 2: TCP_IPV4
- * 3: IPV4 | TCP_IPV4
+ * 1: IPV4 (required by RSS)
+ * 2: TCP_IPV4 (required by RSS)
+ * 3: IPV4 | TCP_IPV4 (required by RSS)
+ * 4: source port
*/
+#define MXGEFW_RSS_HASH_TYPE_IPV4 0x1
+#define MXGEFW_RSS_HASH_TYPE_TCP_IPV4 0x2
+#define MXGEFW_RSS_HASH_TYPE_SRC_PORT 0x4
MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
/* Return data = the max. size of the entire headers of a IPv6 TSO packet.
@@ -260,6 +269,8 @@ enum myri10ge_mcp_cmd_type {
* 0: Linux/FreeBSD style (NIC default)
* 1: NDIS/NetBSD style
*/
+#define MXGEFW_TSO_MODE_LINUX 0
+#define MXGEFW_TSO_MODE_NDIS 1
MXGEFW_CMD_MDIO_READ,
/* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
@@ -286,6 +297,38 @@ enum myri10ge_mcp_cmd_type {
/* Return data = NIC memory offset of mcp_vpump_public_global */
MXGEFW_CMD_RESET_VPUMP,
/* Resets the VPUMP state */
+
+ MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE,
+ /* data0 = mcp_slot type to use.
+ * 0 = the default 4B mcp_slot
+ * 1 = 8B mcp_slot_8
+ */
+#define MXGEFW_RSS_MCP_SLOT_TYPE_MIN 0
+#define MXGEFW_RSS_MCP_SLOT_TYPE_WITH_HASH 1
+
+ MXGEFW_CMD_SET_THROTTLE_FACTOR,
+ /* set the throttle factor for ethp_z8e
+ * data0 = throttle_factor
+ * throttle_factor = 256 * pcie-raw-speed / tx_speed
+ * tx_speed = 256 * pcie-raw-speed / throttle_factor
+ *
+ * For PCI-E x8: pcie-raw-speed == 16Gb/s
+ * For PCI-E x4: pcie-raw-speed == 8Gb/s
+ *
+ * ex1: throttle_factor == 0x1a0 (416), tx_speed == 1.23GB/s == 9.846 Gb/s
+ * ex2: throttle_factor == 0x200 (512), tx_speed == 1.0GB/s == 8 Gb/s
+ *
+ * with tx_boundary == 2048, max-throttle-factor == 8191 => min-speed == 500Mb/s
+ * with tx_boundary == 4096, max-throttle-factor == 4095 => min-speed == 1Gb/s
+ */
+
+ MXGEFW_CMD_VPUMP_UP,
+ /* Allocates VPump Connection, Send Request and Zero copy buffer address tables */
+ MXGEFW_CMD_GET_VPUMP_CLK,
+ /* Get the lanai clock */
+
+ MXGEFW_CMD_GET_DCA_OFFSET,
+ /* offset of dca control for WDMAs */
};
enum myri10ge_mcp_cmd_status {
@@ -302,7 +345,8 @@ enum myri10ge_mcp_cmd_status {
MXGEFW_CMD_ERROR_UNALIGNED,
MXGEFW_CMD_ERROR_NO_MDIO,
MXGEFW_CMD_ERROR_XFP_FAILURE,
- MXGEFW_CMD_ERROR_XFP_ABSENT
+ MXGEFW_CMD_ERROR_XFP_ABSENT,
+ MXGEFW_CMD_ERROR_BAD_PCIE_LINK
};
#define MXGEFW_OLD_IRQ_DATA_LEN 40
diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
index 16a810dd6d51..07d65c2cbb24 100644
--- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
+++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
@@ -1,30 +1,6 @@
#ifndef __MYRI10GE_MCP_GEN_HEADER_H__
#define __MYRI10GE_MCP_GEN_HEADER_H__
-/* this file define a standard header used as a first entry point to
- * exchange information between firmware/driver and driver. The
- * header structure can be anywhere in the mcp. It will usually be in
- * the .data section, because some fields needs to be initialized at
- * compile time.
- * The 32bit word at offset MX_HEADER_PTR_OFFSET in the mcp must
- * contains the location of the header.
- *
- * Typically a MCP will start with the following:
- * .text
- * .space 52 ! to help catch MEMORY_INT errors
- * bt start ! jump to real code
- * nop
- * .long _gen_mcp_header
- *
- * The source will have a definition like:
- *
- * mcp_gen_header_t gen_mcp_header = {
- * .header_length = sizeof(mcp_gen_header_t),
- * .mcp_type = MCP_TYPE_XXX,
- * .version = "something $Id: mcp_gen_header.h,v 1.2 2006/05/13 10:04:35 bgoglin Exp $",
- * .mcp_globals = (unsigned)&Globals
- * };
- */
#define MCP_HEADER_PTR_OFFSET 0x3c
@@ -32,13 +8,14 @@
#define MCP_TYPE_PCIE 0x70636965 /* "PCIE" pcie-only MCP */
#define MCP_TYPE_ETH 0x45544820 /* "ETH " */
#define MCP_TYPE_MCP0 0x4d435030 /* "MCP0" */
+#define MCP_TYPE_DFLT 0x20202020 /* " " */
struct mcp_gen_header {
/* the first 4 fields are filled at compile time */
unsigned header_length;
__be32 mcp_type;
char version[128];
- unsigned mcp_globals; /* pointer to mcp-type specific structure */
+ unsigned mcp_private; /* pointer to mcp-type specific structure */
/* filled by the MCP at run-time */
unsigned sram_size;
@@ -53,6 +30,18 @@ struct mcp_gen_header {
*
* Never remove any field. Keep everything naturally align.
*/
+
+ /* Specifies if the running mcp is mcp0, 1, or 2. */
+ unsigned char mcp_index;
+ unsigned char disable_rabbit;
+ unsigned char unaligned_tlp;
+ unsigned char pad1;
+ unsigned counters_addr;
+ unsigned copy_block_info; /* for small mcps loaded with "lload -d" */
+ unsigned short handoff_id_major; /* must be equal */
+ unsigned short handoff_id_caps; /* bitfield: new mcp must have superset */
+ unsigned msix_table_addr; /* start address of msix table in firmware */
+ /* 8 */
};
#endif /* __MYRI10GE_MCP_GEN_HEADER_H__ */
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 4009c4ce96b4..918f802fe089 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -1,6 +1,6 @@
/* niu.c: Neptune ethernet driver.
*
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -33,8 +33,8 @@
#define DRV_MODULE_NAME "niu"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.8"
-#define DRV_MODULE_RELDATE "April 24, 2008"
+#define DRV_MODULE_VERSION "0.9"
+#define DRV_MODULE_RELDATE "May 4, 2008"
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -865,7 +865,6 @@ static int link_status_1g_serdes(struct niu *np, int *link_up_p)
return 0;
}
-
static int link_status_10g_serdes(struct niu *np, int *link_up_p)
{
unsigned long flags;
@@ -900,7 +899,6 @@ static int link_status_10g_serdes(struct niu *np, int *link_up_p)
return 0;
}
-
static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
{
struct niu_link_config *lp = &np->link_config;
@@ -957,7 +955,6 @@ out:
return err;
}
-
static int bcm8704_reset(struct niu *np)
{
int err, limit;
@@ -1357,8 +1354,6 @@ static int mii_reset(struct niu *np)
return 0;
}
-
-
static int xcvr_init_1g_rgmii(struct niu *np)
{
int err;
@@ -1419,7 +1414,6 @@ static int xcvr_init_1g_rgmii(struct niu *np)
return 0;
}
-
static int mii_init_common(struct niu *np)
{
struct niu_link_config *lp = &np->link_config;
@@ -7008,31 +7002,20 @@ static int __devinit niu_phy_type_prop_decode(struct niu *np,
return 0;
}
-/* niu board models have a trailing dash version incremented
- * with HW rev change. Need to ingnore the dash version while
- * checking for match
- *
- * for example, for the 10G card the current vpd.board_model
- * is 501-5283-04, of which -04 is the dash version and have
- * to be ignored
- */
-static int niu_board_model_match(struct niu *np, const char *model)
-{
- return !strncmp(np->vpd.board_model, model, strlen(model));
-}
-
static int niu_pci_vpd_get_nports(struct niu *np)
{
int ports = 0;
- if ((niu_board_model_match(np, NIU_QGC_LP_BM_STR)) ||
- (niu_board_model_match(np, NIU_QGC_PEM_BM_STR)) ||
- (niu_board_model_match(np, NIU_ALONSO_BM_STR))) {
+ if ((!strcmp(np->vpd.model, NIU_QGC_LP_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_QGC_PEM_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_MARAMBA_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR))) {
ports = 4;
- } else if ((niu_board_model_match(np, NIU_2XGF_LP_BM_STR)) ||
- (niu_board_model_match(np, NIU_2XGF_PEM_BM_STR)) ||
- (niu_board_model_match(np, NIU_FOXXY_BM_STR)) ||
- (niu_board_model_match(np, NIU_2XGF_MRVL_BM_STR))) {
+ } else if ((!strcmp(np->vpd.model, NIU_2XGF_LP_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_2XGF_PEM_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) ||
+ (!strcmp(np->vpd.model, NIU_2XGF_MRVL_MDL_STR))) {
ports = 2;
}
@@ -7053,8 +7036,8 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
return;
}
- if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
- !strcmp(np->vpd.model, "SUNW,CP3260")) {
+ if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
+ !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
np->flags |= NIU_FLAGS_10G;
np->flags &= ~NIU_FLAGS_FIBER;
np->flags |= NIU_FLAGS_XCVR_SERDES;
@@ -7065,7 +7048,7 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
}
if (np->flags & NIU_FLAGS_10G)
np->mac_xcvr = MAC_XCVR_XPCS;
- } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+ } else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
NIU_FLAGS_HOTPLUG_PHY);
} else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
@@ -7264,8 +7247,11 @@ static int __devinit niu_get_and_validate_port(struct niu *np)
parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
ESPC_NUM_PORTS_MACS_VAL;
+ /* All of the current probing methods fail on
+ * Maramba on-board parts.
+ */
if (!parent->num_ports)
- return -ENODEV;
+ parent->num_ports = 4;
}
}
}
@@ -7538,8 +7524,8 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
u32 val;
int err;
- if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
- !strcmp(np->vpd.model, "SUNW,CP3260")) {
+ if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) ||
+ !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) {
num_10g = 0;
num_1g = 2;
parent->plat_type = PLAT_TYPE_ATCA_CP3220;
@@ -7548,7 +7534,7 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
phy_encode(PORT_TYPE_1G, 1) |
phy_encode(PORT_TYPE_1G, 2) |
phy_encode(PORT_TYPE_1G, 3));
- } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+ } else if (!strcmp(np->vpd.model, NIU_FOXXY_MDL_STR)) {
num_10g = 2;
num_1g = 0;
parent->num_ports = 2;
@@ -7943,6 +7929,7 @@ static int __devinit niu_get_of_props(struct niu *np)
struct device_node *dp;
const char *phy_type;
const u8 *mac_addr;
+ const char *model;
int prop_len;
if (np->parent->plat_type == PLAT_TYPE_NIU)
@@ -7997,6 +7984,11 @@ static int __devinit niu_get_of_props(struct niu *np)
memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+ model = of_get_property(dp, "model", &prop_len);
+
+ if (model)
+ strcpy(np->vpd.model, model);
+
return 0;
#else
return -EINVAL;
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 97ffbe137bcb..12fd570b9423 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -2946,6 +2946,15 @@ struct rx_ring_info {
#define NIU_ALONSO_BM_STR "373-0202"
#define NIU_FOXXY_BM_STR "501-7961"
#define NIU_2XGF_MRVL_BM_STR "SK-6E82"
+#define NIU_QGC_LP_MDL_STR "SUNW,pcie-qgc"
+#define NIU_2XGF_LP_MDL_STR "SUNW,pcie-2xgf"
+#define NIU_QGC_PEM_MDL_STR "SUNW,pcie-qgc-pem"
+#define NIU_2XGF_PEM_MDL_STR "SUNW,pcie-2xgf-pem"
+#define NIU_ALONSO_MDL_STR "SUNW,CP3220"
+#define NIU_KIMI_MDL_STR "SUNW,CP3260"
+#define NIU_MARAMBA_MDL_STR "SUNW,pcie-neptune"
+#define NIU_FOXXY_MDL_STR "SUNW,pcie-rfem"
+#define NIU_2XGF_MRVL_MDL_STR "SysKonnect,pcie-2xgf"
#define NIU_VPD_MIN_MAJOR 3
#define NIU_VPD_MIN_MINOR 4
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 4eb322e5273d..a1c454dbc164 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -22,12 +22,8 @@
*************************************************************************/
#define DRV_NAME "pcnet32"
-#ifdef CONFIG_PCNET32_NAPI
-#define DRV_VERSION "1.34-NAPI"
-#else
-#define DRV_VERSION "1.34"
-#endif
-#define DRV_RELDATE "14.Aug.2007"
+#define DRV_VERSION "1.35"
+#define DRV_RELDATE "21.Apr.2008"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -445,30 +441,24 @@ static struct pcnet32_access pcnet32_dwio = {
static void pcnet32_netif_stop(struct net_device *dev)
{
-#ifdef CONFIG_PCNET32_NAPI
struct pcnet32_private *lp = netdev_priv(dev);
-#endif
+
dev->trans_start = jiffies;
-#ifdef CONFIG_PCNET32_NAPI
napi_disable(&lp->napi);
-#endif
netif_tx_disable(dev);
}
static void pcnet32_netif_start(struct net_device *dev)
{
-#ifdef CONFIG_PCNET32_NAPI
struct pcnet32_private *lp = netdev_priv(dev);
ulong ioaddr = dev->base_addr;
u16 val;
-#endif
+
netif_wake_queue(dev);
-#ifdef CONFIG_PCNET32_NAPI
val = lp->a.read_csr(ioaddr, CSR3);
val &= 0x00ff;
lp->a.write_csr(ioaddr, CSR3, val);
napi_enable(&lp->napi);
-#endif
}
/*
@@ -911,11 +901,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
rc = 1; /* default to fail */
if (netif_running(dev))
-#ifdef CONFIG_PCNET32_NAPI
pcnet32_netif_stop(dev);
-#else
- pcnet32_close(dev);
-#endif
spin_lock_irqsave(&lp->lock, flags);
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
@@ -1046,7 +1032,6 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
a->write_bcr(ioaddr, 32, (x & ~0x0002));
-#ifdef CONFIG_PCNET32_NAPI
if (netif_running(dev)) {
pcnet32_netif_start(dev);
pcnet32_restart(dev, CSR0_NORMAL);
@@ -1055,16 +1040,6 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
}
spin_unlock_irqrestore(&lp->lock, flags);
-#else
- if (netif_running(dev)) {
- spin_unlock_irqrestore(&lp->lock, flags);
- pcnet32_open(dev);
- } else {
- pcnet32_purge_rx_ring(dev);
- lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
- spin_unlock_irqrestore(&lp->lock, flags);
- }
-#endif
return (rc);
} /* end pcnet32_loopback_test */
@@ -1270,11 +1245,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
}
dev->stats.rx_bytes += skb->len;
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_PCNET32_NAPI
netif_receive_skb(skb);
-#else
- netif_rx(skb);
-#endif
dev->last_rx = jiffies;
dev->stats.rx_packets++;
return;
@@ -1403,7 +1374,6 @@ static int pcnet32_tx(struct net_device *dev)
return must_restart;
}
-#ifdef CONFIG_PCNET32_NAPI
static int pcnet32_poll(struct napi_struct *napi, int budget)
{
struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi);
@@ -1442,7 +1412,6 @@ static int pcnet32_poll(struct napi_struct *napi, int budget)
}
return work_done;
}
-#endif
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
@@ -1864,9 +1833,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
/* napi.weight is used in both the napi and non-napi cases */
lp->napi.weight = lp->rx_ring_size / 2;
-#ifdef CONFIG_PCNET32_NAPI
netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2);
-#endif
if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
@@ -2297,9 +2264,7 @@ static int pcnet32_open(struct net_device *dev)
goto err_free_ring;
}
-#ifdef CONFIG_PCNET32_NAPI
napi_enable(&lp->napi);
-#endif
/* Re-initialize the PCNET32, and start it when done. */
lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
@@ -2623,7 +2588,6 @@ pcnet32_interrupt(int irq, void *dev_id)
dev->name, csr0);
/* unlike for the lance, there is no restart needed */
}
-#ifdef CONFIG_PCNET32_NAPI
if (netif_rx_schedule_prep(dev, &lp->napi)) {
u16 val;
/* set interrupt masks */
@@ -2634,24 +2598,9 @@ pcnet32_interrupt(int irq, void *dev_id)
__netif_rx_schedule(dev, &lp->napi);
break;
}
-#else
- pcnet32_rx(dev, lp->napi.weight);
- if (pcnet32_tx(dev)) {
- /* reset the chip to clear the error condition, then restart */
- lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
- pcnet32_restart(dev, CSR0_START);
- netif_wake_queue(dev);
- }
-#endif
csr0 = lp->a.read_csr(ioaddr, CSR0);
}
-#ifndef CONFIG_PCNET32_NAPI
- /* Set interrupt enable. */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
-#endif
-
if (netif_msg_intr(lp))
printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
dev->name, lp->a.read_csr(ioaddr, CSR0));
@@ -2670,9 +2619,7 @@ static int pcnet32_close(struct net_device *dev)
del_timer_sync(&lp->watchdog_timer);
netif_stop_queue(dev);
-#ifdef CONFIG_PCNET32_NAPI
napi_disable(&lp->napi);
-#endif
spin_lock_irqsave(&lp->lock, flags);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3ac8529bb92c..6bf9e76b0a00 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -48,7 +48,7 @@ config VITESSE_PHY
config SMSC_PHY
tristate "Drivers for SMSC PHYs"
---help---
- Currently supports the LAN83C185 PHY
+ Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 3c18bb594957..45cc2914d347 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -547,7 +547,7 @@ static void phy_force_reduction(struct phy_device *phydev)
* Must not be called from interrupt context, or while the
* phydev->lock is held.
*/
-void phy_error(struct phy_device *phydev)
+static void phy_error(struct phy_device *phydev)
{
mutex_lock(&phydev->lock);
phydev->state = PHY_HALTED;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ddf8d51832a6..ac3c01d28fdf 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -256,7 +256,7 @@ void phy_prepare_link(struct phy_device *phydev,
/**
* phy_connect - connect an ethernet device to a PHY device
* @dev: the network device to connect
- * @phy_id: the PHY device to connect
+ * @bus_id: the id string of the PHY device to connect
* @handler: callback function for state change notifications
* @flags: PHY device's dev_flags
* @interface: PHY device's interface
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index b1d8ed40ad98..73baa7a3bb0e 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -12,6 +12,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
+ * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@smsc.com
+ *
*/
#include <linux/kernel.h>
@@ -38,7 +40,7 @@
(MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
-static int lan83c185_config_intr(struct phy_device *phydev)
+static int smsc_phy_config_intr(struct phy_device *phydev)
{
int rc = phy_write (phydev, MII_LAN83C185_IM,
((PHY_INTERRUPT_ENABLED == phydev->interrupts)
@@ -48,16 +50,16 @@ static int lan83c185_config_intr(struct phy_device *phydev)
return rc < 0 ? rc : 0;
}
-static int lan83c185_ack_interrupt(struct phy_device *phydev)
+static int smsc_phy_ack_interrupt(struct phy_device *phydev)
{
int rc = phy_read (phydev, MII_LAN83C185_ISF);
return rc < 0 ? rc : 0;
}
-static int lan83c185_config_init(struct phy_device *phydev)
+static int smsc_phy_config_init(struct phy_device *phydev)
{
- return lan83c185_ack_interrupt (phydev);
+ return smsc_phy_ack_interrupt (phydev);
}
@@ -73,22 +75,87 @@ static struct phy_driver lan83c185_driver = {
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
- .config_init = lan83c185_config_init,
+ .config_init = smsc_phy_config_init,
/* IRQ related */
- .ack_interrupt = lan83c185_ack_interrupt,
- .config_intr = lan83c185_config_intr,
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8187_driver = {
+ .phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8187",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = smsc_phy_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8700_driver = {
+ .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8700",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = smsc_phy_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static int __init smsc_init(void)
{
- return phy_driver_register (&lan83c185_driver);
+ int ret;
+
+ ret = phy_driver_register (&lan83c185_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register (&lan8187_driver);
+ if (ret)
+ goto err2;
+
+ ret = phy_driver_register (&lan8700_driver);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ phy_driver_unregister (&lan8187_driver);
+err2:
+ phy_driver_unregister (&lan83c185_driver);
+err1:
+ return ret;
}
static void __exit smsc_exit(void)
{
+ phy_driver_unregister (&lan8700_driver);
+ phy_driver_unregister (&lan8187_driver);
phy_driver_unregister (&lan83c185_driver);
}
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index f023d5b67e6e..f1a52def1241 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -158,6 +158,9 @@ ppp_asynctty_open(struct tty_struct *tty)
struct asyncppp *ap;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
err = -ENOMEM;
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (!ap)
@@ -358,9 +361,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
ap_put(ap);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static void
@@ -676,7 +677,7 @@ ppp_async_push(struct asyncppp *ap)
if (!tty_stuffed && ap->optr < ap->olim) {
avail = ap->olim - ap->optr;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, ap->optr, avail);
+ sent = tty->ops->write(tty, ap->optr, avail);
if (sent < 0)
goto flush; /* error, e.g. loss of CD */
ap->optr += sent;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index d3207c0da895..1f4ca2b54a73 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2458,6 +2458,7 @@ ppp_create_interface(int unit, int *retp)
out3:
atomic_dec(&ppp_unit_count);
+ unregister_netdev(dev);
out2:
mutex_unlock(&all_ppp_mutex);
free_netdev(dev);
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 0d80fa546719..b8f0369a71e7 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -207,6 +207,9 @@ ppp_sync_open(struct tty_struct *tty)
struct syncppp *ap;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
if (!ap)
@@ -398,9 +401,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
sp_put(ap);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static void
@@ -653,7 +654,7 @@ ppp_sync_push(struct syncppp *ap)
tty_stuffed = 0;
if (!tty_stuffed && ap->tpkt) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, ap->tpkt->data, ap->tpkt->len);
+ sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len);
if (sent < 0)
goto flush; /* error, e.g. loss of CD */
if (sent < ap->tpkt->len) {
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 4fad4ddb3504..58a26a47af29 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1052,11 +1052,9 @@ static int __init pppoe_proc_init(void)
{
struct proc_dir_entry *p;
- p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net);
+ p = proc_net_fops_create(&init_net, "pppoe", S_IRUGO, &pppoe_seq_fops);
if (!p)
return -ENOMEM;
-
- p->proc_fops = &pppoe_seq_fops;
return 0;
}
#else /* CONFIG_PROC_FS */
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 3d10ca050b79..79359919335b 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -1621,9 +1621,16 @@ out_no_ppp:
end:
release_sock(sk);
- if (error != 0)
- PRINTK(session ? session->debug : -1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
- "%s: connect failed: %d\n", session->name, error);
+ if (error != 0) {
+ if (session)
+ PRINTK(session->debug,
+ PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+ "%s: connect failed: %d\n",
+ session->name, error);
+ else
+ PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+ "connect failed: %d\n", error);
+ }
return error;
}
@@ -2469,12 +2476,12 @@ static int __init pppol2tp_init(void)
goto out_unregister_pppol2tp_proto;
#ifdef CONFIG_PROC_FS
- pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net);
+ pppol2tp_proc = proc_net_fops_create(&init_net, "pppol2tp", 0,
+ &pppol2tp_proc_fops);
if (!pppol2tp_proc) {
err = -ENOMEM;
goto out_unregister_pppox_proto;
}
- pppol2tp_proc->proc_fops = &pppol2tp_proc_fops;
#endif /* CONFIG_PROC_FS */
printk(KERN_INFO "PPPoL2TP kernel driver, %s\n",
PPPOL2TP_DRV_VERSION);
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 0d32123085e9..1dae1f2ed813 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -2474,6 +2474,8 @@ static void gelic_wl_free(struct gelic_wl_info *wl)
pr_debug("%s: <-\n", __func__);
+ free_page((unsigned long)wl->buf);
+
pr_debug("%s: destroy queues\n", __func__);
destroy_workqueue(wl->eurus_cmd_queue);
destroy_workqueue(wl->event_queue);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 3acfeeabdee1..657242504621 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1617,6 +1617,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->dev = dev;
+ tp->pci_dev = pdev;
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
/* enable device (incl. PCI PM wakeup and hotplug setup) */
@@ -1705,18 +1706,18 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8169_print_mac_version(tp);
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
+ for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
if (tp->mac_version == rtl_chip_info[i].mac_version)
break;
}
- if (i < 0) {
+ if (i == ARRAY_SIZE(rtl_chip_info)) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
dev_printk(KERN_DEBUG, &pdev->dev,
"unknown chip version, assuming %s\n",
rtl_chip_info[0].name);
}
- i++;
+ i = 0;
}
tp->chipset = i;
@@ -1777,7 +1778,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
tp->intr_mask = 0xffff;
- tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
tp->align = cfg->align;
tp->hw_start = cfg->hw_start;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index e7fd08adbbac..2b8fd68bc516 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -77,7 +77,7 @@ static int rionet_capable = 1;
* could be made into a hash table to save memory depending
* on system trade-offs.
*/
-static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
+static struct rio_dev **rionet_active;
#define is_rionet_capable(pef, src_ops, dst_ops) \
((pef & RIO_PEF_INB_MBOX) && \
@@ -195,7 +195,8 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
if (eth->h_dest[0] & 0x01) {
- for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++)
+ for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
+ i++)
if (rionet_active[i])
rionet_queue_tx_msg(skb, ndev,
rionet_active[i]);
@@ -385,6 +386,8 @@ static void rionet_remove(struct rio_dev *rdev)
struct net_device *ndev = NULL;
struct rionet_peer *peer, *tmp;
+ free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
+ __ilog2(sizeof(void *)) + 4 : 0);
unregister_netdev(ndev);
kfree(ndev);
@@ -443,6 +446,15 @@ static int rionet_setup_netdev(struct rio_mport *mport)
goto out;
}
+ rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
+ mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0);
+ if (!rionet_active) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset((void *)rionet_active, 0, sizeof(void *) *
+ RIO_MAX_ROUTE_ENTRIES(mport->sys_size));
+
/* Set up private area */
rnet = (struct rionet_private *)ndev->priv;
rnet->mport = mport;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 157fd932e951..523478ebfd69 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -86,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.22"
+#define DRV_VERSION "2.0.26.23"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -809,6 +809,7 @@ static int init_shared_mem(struct s2io_nic *nic)
config->rx_cfg[i].num_rxd - 1;
mac_control->rings[i].nic = nic;
mac_control->rings[i].ring_no = i;
+ mac_control->rings[i].lro = lro_enable;
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode] + 1);
@@ -1560,113 +1561,112 @@ static int init_nic(struct s2io_nic *nic)
writeq(val64, &bar0->tx_fifo_partition_0);
/* Filling the Rx round robin registers as per the
- * number of Rings and steering based on QoS.
- */
+ * number of Rings and steering based on QoS with
+ * equal priority.
+ */
switch (config->rx_ring_num) {
case 1:
+ val64 = 0x0;
+ writeq(val64, &bar0->rx_w_round_robin_0);
+ writeq(val64, &bar0->rx_w_round_robin_1);
+ writeq(val64, &bar0->rx_w_round_robin_2);
+ writeq(val64, &bar0->rx_w_round_robin_3);
+ writeq(val64, &bar0->rx_w_round_robin_4);
+
val64 = 0x8080808080808080ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 2:
- val64 = 0x0000010000010000ULL;
+ val64 = 0x0001000100010001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0100000100000100ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0001000001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0000010000010000ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0100000000000000ULL;
+ val64 = 0x0001000100000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080808040404040ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 3:
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0001020000010001ULL;
+ val64 = 0x0200010200010200ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0200000100010200ULL;
+ val64 = 0x0102000102000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001020000000000ULL;
+ val64 = 0x0200010200000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080804040402020ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 4:
- val64 = 0x0001020300010200ULL;
+ val64 = 0x0001020300010203ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0100000102030001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0200010000010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0203000100000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201010ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 5:
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0001020304000102ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0304000102030400ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0102030400010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0400010203040001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001000000000000ULL;
+ val64 = 0x0203040000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201008ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 6:
- val64 = 0x0001020304000102ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0304050001020001ULL;
+ val64 = 0x0203040500010203ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0203000100000102ULL;
+ val64 = 0x0405000102030405ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304000102030405ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001000200000000ULL;
+ val64 = 0x0203040500000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020100804ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 7:
- val64 = 0x0001020001020300ULL;
+ val64 = 0x0001020304050600ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0102030400010203ULL;
+ val64 = 0x0102030405060001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0405060001020001ULL;
+ val64 = 0x0203040506000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304050000010200ULL;
+ val64 = 0x0304050600010203ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0102030000000000ULL;
+ val64 = 0x0405060000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080402010080402ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 8:
- val64 = 0x0001020300040105ULL;
+ val64 = 0x0001020304050607ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0200030106000204ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0103000502010007ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304010002060500ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0103020400000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8040201008040201ULL;
@@ -2499,8 +2499,7 @@ static void stop_nic(struct s2io_nic *nic)
/**
* fill_rx_buffers - Allocates the Rx side skbs
- * @nic: device private variable
- * @ring_no: ring number
+ * @ring_info: per ring structure
* Description:
* The function allocates Rx side skbs and puts the physical
* address of these buffers into the RxD buffer pointers, so that the NIC
@@ -2518,103 +2517,94 @@ static void stop_nic(struct s2io_nic *nic)
* SUCCESS on success or an appropriate -ve value on failure.
*/
-static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+static int fill_rx_buffers(struct ring_info *ring)
{
- struct net_device *dev = nic->dev;
struct sk_buff *skb;
struct RxD_t *rxdp;
- int off, off1, size, block_no, block_no1;
+ int off, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
- struct mac_info *mac_control;
- struct config_param *config;
u64 tmp;
struct buffAdd *ba;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
+ int rxd_index = 0;
struct RxD1 *rxdp1;
struct RxD3 *rxdp3;
- struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
+ struct swStat *stats = &ring->nic->mac_control.stats_info->sw_stat;
- mac_control = &nic->mac_control;
- config = &nic->config;
- alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
- atomic_read(&nic->rx_bufs_left[ring_no]);
+ alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left;
- block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
- off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
+ block_no1 = ring->rx_curr_get_info.block_index;
while (alloc_tab < alloc_cnt) {
- block_no = mac_control->rings[ring_no].rx_curr_put_info.
- block_index;
- off = mac_control->rings[ring_no].rx_curr_put_info.offset;
+ block_no = ring->rx_curr_put_info.block_index;
- rxdp = mac_control->rings[ring_no].
- rx_blocks[block_no].rxds[off].virt_addr;
+ off = ring->rx_curr_put_info.offset;
+
+ rxdp = ring->rx_blocks[block_no].rxds[off].virt_addr;
+
+ rxd_index = off + 1;
+ if (block_no)
+ rxd_index += (block_no * ring->rxd_count);
- if ((block_no == block_no1) && (off == off1) &&
- (rxdp->Host_Control)) {
+ if ((block_no == block_no1) &&
+ (off == ring->rx_curr_get_info.offset) &&
+ (rxdp->Host_Control)) {
DBG_PRINT(INTR_DBG, "%s: Get and Put",
- dev->name);
+ ring->dev->name);
DBG_PRINT(INTR_DBG, " info equated\n");
goto end;
}
- if (off && (off == rxd_count[nic->rxd_mode])) {
- mac_control->rings[ring_no].rx_curr_put_info.
- block_index++;
- if (mac_control->rings[ring_no].rx_curr_put_info.
- block_index == mac_control->rings[ring_no].
- block_count)
- mac_control->rings[ring_no].rx_curr_put_info.
- block_index = 0;
- block_no = mac_control->rings[ring_no].
- rx_curr_put_info.block_index;
- if (off == rxd_count[nic->rxd_mode])
- off = 0;
- mac_control->rings[ring_no].rx_curr_put_info.
- offset = off;
- rxdp = mac_control->rings[ring_no].
- rx_blocks[block_no].block_virt_addr;
+ if (off && (off == ring->rxd_count)) {
+ ring->rx_curr_put_info.block_index++;
+ if (ring->rx_curr_put_info.block_index ==
+ ring->block_count)
+ ring->rx_curr_put_info.block_index = 0;
+ block_no = ring->rx_curr_put_info.block_index;
+ off = 0;
+ ring->rx_curr_put_info.offset = off;
+ rxdp = ring->rx_blocks[block_no].block_virt_addr;
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
- dev->name, rxdp);
+ ring->dev->name, rxdp);
+
}
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
- ((nic->rxd_mode == RXD_MODE_3B) &&
+ ((ring->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & s2BIT(0)))) {
- mac_control->rings[ring_no].rx_curr_put_info.
- offset = off;
+ ring->rx_curr_put_info.offset = off;
goto end;
}
/* calculate size of skb based on ring mode */
- size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
+ size = ring->mtu + HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
- if (nic->rxd_mode == RXD_MODE_1)
+ if (ring->rxd_mode == RXD_MODE_1)
size += NET_IP_ALIGN;
else
- size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
+ size = ring->mtu + ALIGN_SIZE + BUF0_LEN + 4;
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
- DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name);
DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
- nic->mac_control.stats_info->sw_stat. \
- mem_alloc_fail_cnt++;
+ stats->mem_alloc_fail_cnt++;
+
return -ENOMEM ;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
- += skb->truesize;
- if (nic->rxd_mode == RXD_MODE_1) {
+ stats->mem_allocated += skb->truesize;
+
+ if (ring->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
rxdp1 = (struct RxD1*)rxdp;
memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
rxdp1->Buffer0_ptr = pci_map_single
- (nic->pdev, skb->data, size - NET_IP_ALIGN,
+ (ring->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
if( (rxdp1->Buffer0_ptr == 0) ||
(rxdp1->Buffer0_ptr ==
@@ -2623,8 +2613,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp->Control_2 =
SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
-
- } else if (nic->rxd_mode == RXD_MODE_3B) {
+ rxdp->Host_Control = (unsigned long) (skb);
+ } else if (ring->rxd_mode == RXD_MODE_3B) {
/*
* 2 buffer mode -
* 2 buffer mode provides 128
@@ -2640,7 +2630,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp3->Buffer0_ptr = Buffer0_ptr;
rxdp3->Buffer1_ptr = Buffer1_ptr;
- ba = &mac_control->rings[ring_no].ba[block_no][off];
+ ba = &ring->ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
tmp += ALIGN_SIZE;
@@ -2650,10 +2640,10 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
if (!(rxdp3->Buffer0_ptr))
rxdp3->Buffer0_ptr =
- pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
- PCI_DMA_FROMDEVICE);
+ pci_map_single(ring->pdev, ba->ba_0,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
else
- pci_dma_sync_single_for_device(nic->pdev,
+ pci_dma_sync_single_for_device(ring->pdev,
(dma_addr_t) rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer0_ptr == 0) ||
@@ -2661,7 +2651,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
goto pci_map_failed;
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
- if (nic->rxd_mode == RXD_MODE_3B) {
+ if (ring->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
/*
@@ -2669,39 +2659,42 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* L4 payload
*/
rxdp3->Buffer2_ptr = pci_map_single
- (nic->pdev, skb->data, dev->mtu + 4,
+ (ring->pdev, skb->data, ring->mtu + 4,
PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer2_ptr == 0) ||
(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
goto pci_map_failed;
- rxdp3->Buffer1_ptr =
- pci_map_single(nic->pdev,
+ if (!rxdp3->Buffer1_ptr)
+ rxdp3->Buffer1_ptr =
+ pci_map_single(ring->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
+
if( (rxdp3->Buffer1_ptr == 0) ||
(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
pci_unmap_single
- (nic->pdev,
- (dma_addr_t)rxdp3->Buffer2_ptr,
- dev->mtu + 4,
+ (ring->pdev,
+ (dma_addr_t)(unsigned long)
+ skb->data,
+ ring->mtu + 4,
PCI_DMA_FROMDEVICE);
goto pci_map_failed;
}
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
- (dev->mtu + 4);
+ (ring->mtu + 4);
}
rxdp->Control_2 |= s2BIT(0);
+ rxdp->Host_Control = (unsigned long) (skb);
}
- rxdp->Host_Control = (unsigned long) (skb);
if (alloc_tab & ((1 << rxsync_frequency) - 1))
rxdp->Control_1 |= RXD_OWN_XENA;
off++;
- if (off == (rxd_count[nic->rxd_mode] + 1))
+ if (off == (ring->rxd_count + 1))
off = 0;
- mac_control->rings[ring_no].rx_curr_put_info.offset = off;
+ ring->rx_curr_put_info.offset = off;
rxdp->Control_2 |= SET_RXD_MARKER;
if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
@@ -2711,7 +2704,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
first_rxdp = rxdp;
}
- atomic_inc(&nic->rx_bufs_left[ring_no]);
+ ring->rx_bufs_left += 1;
alloc_tab++;
}
@@ -2783,7 +2776,7 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
}
sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
dev_kfree_skb(skb);
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ mac_control->rings[ring_no].rx_bufs_left -= 1;
}
}
@@ -2814,7 +2807,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
mac_control->rings[i].rx_curr_get_info.block_index = 0;
mac_control->rings[i].rx_curr_put_info.offset = 0;
mac_control->rings[i].rx_curr_get_info.offset = 0;
- atomic_set(&sp->rx_bufs_left[i], 0);
+ mac_control->rings[i].rx_bufs_left = 0;
DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
dev->name, buf_cnt, i);
}
@@ -2864,7 +2857,7 @@ static int s2io_poll(struct napi_struct *napi, int budget)
netif_rx_complete(dev, napi);
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@@ -2877,7 +2870,7 @@ static int s2io_poll(struct napi_struct *napi, int budget)
no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@@ -2928,7 +2921,7 @@ static void s2io_netpoll(struct net_device *dev)
rx_intr_handler(&mac_control->rings[i]);
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
@@ -2953,8 +2946,6 @@ static void s2io_netpoll(struct net_device *dev)
*/
static void rx_intr_handler(struct ring_info *ring_data)
{
- struct s2io_nic *nic = ring_data->nic;
- struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
@@ -2977,33 +2968,34 @@ static void rx_intr_handler(struct ring_info *ring_data)
*/
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
- DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
+ DBG_PRINT(INTR_DBG, "%s: Ring Full\n",
+ ring_data->dev->name);
break;
}
skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: The skb is ",
- dev->name);
+ ring_data->dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
return;
}
- if (nic->rxd_mode == RXD_MODE_1) {
+ if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1*)rxdp;
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp1->Buffer0_ptr,
- dev->mtu +
+ ring_data->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
- } else if (nic->rxd_mode == RXD_MODE_3B) {
+ } else if (ring_data->rxd_mode == RXD_MODE_3B) {
rxdp3 = (struct RxD3*)rxdp;
- pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer2_ptr,
- dev->mtu + 4,
+ ring_data->mtu + 4,
PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@@ -3012,7 +3004,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
ring_data->rx_curr_get_info.offset = get_info.offset;
rxdp = ring_data->rx_blocks[get_block].
rxds[get_info.offset].virt_addr;
- if (get_info.offset == rxd_count[nic->rxd_mode]) {
+ if (get_info.offset == rxd_count[ring_data->rxd_mode]) {
get_info.offset = 0;
ring_data->rx_curr_get_info.offset = get_info.offset;
get_block++;
@@ -3022,19 +3014,21 @@ static void rx_intr_handler(struct ring_info *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
- nic->pkts_to_process -= 1;
- if ((napi) && (!nic->pkts_to_process))
- break;
+ if(ring_data->nic->config.napi){
+ ring_data->nic->pkts_to_process -= 1;
+ if (!ring_data->nic->pkts_to_process)
+ break;
+ }
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
}
- if (nic->lro) {
+ if (ring_data->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *lro = &nic->lro0_n[i];
+ struct lro *lro = &ring_data->lro0_n[i];
if (lro->in_use) {
- update_L3L4_header(nic, lro);
+ update_L3L4_header(ring_data->nic, lro);
queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro);
}
@@ -4333,10 +4327,10 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct ring_info *ring)
{
- if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ if (fill_rx_buffers(ring) == -ENOMEM) {
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
@@ -4351,7 +4345,7 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
return IRQ_HANDLED;
rx_intr_handler(ring);
- s2io_chk_rx_buffers(sp, ring->ring_no);
+ s2io_chk_rx_buffers(ring);
return IRQ_HANDLED;
}
@@ -4809,7 +4803,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
*/
if (!config->napi) {
for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
+ s2io_chk_rx_buffers(&mac_control->rings[i]);
}
writeq(sp->general_int_mask, &bar0->general_int_mask);
readl(&bar0->general_int_status);
@@ -4866,6 +4860,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
struct s2io_nic *sp = dev->priv;
struct mac_info *mac_control;
struct config_param *config;
+ int i;
mac_control = &sp->mac_control;
@@ -4885,6 +4880,13 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
sp->stats.rx_length_errors =
le64_to_cpu(mac_control->stats_info->rmac_long_frms);
+ /* collect per-ring rx_packets and rx_bytes */
+ sp->stats.rx_packets = sp->stats.rx_bytes = 0;
+ for (i = 0; i < config->rx_ring_num; i++) {
+ sp->stats.rx_packets += mac_control->rings[i].rx_packets;
+ sp->stats.rx_bytes += mac_control->rings[i].rx_bytes;
+ }
+
return (&sp->stats);
}
@@ -7157,7 +7159,9 @@ static int s2io_card_up(struct s2io_nic * sp)
config = &sp->config;
for (i = 0; i < config->rx_ring_num; i++) {
- if ((ret = fill_rx_buffers(sp, i))) {
+ mac_control->rings[i].mtu = dev->mtu;
+ ret = fill_rx_buffers(&mac_control->rings[i]);
+ if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
dev->name);
s2io_reset(sp);
@@ -7165,7 +7169,7 @@ static int s2io_card_up(struct s2io_nic * sp)
return -ENOMEM;
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
- atomic_read(&sp->rx_bufs_left[i]));
+ mac_control->rings[i].rx_bufs_left);
}
/* Initialise napi */
@@ -7300,7 +7304,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
struct s2io_nic *sp = ring_data->nic;
- struct net_device *dev = (struct net_device *) sp->dev;
+ struct net_device *dev = (struct net_device *) ring_data->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
@@ -7377,19 +7381,19 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
sp->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ ring_data->rx_bufs_left -= 1;
rxdp->Host_Control = 0;
return 0;
}
}
/* Updating statistics */
- sp->stats.rx_packets++;
+ ring_data->rx_packets++;
rxdp->Host_Control = 0;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
- sp->stats.rx_bytes += len;
+ ring_data->rx_bytes += len;
skb_put(skb, len);
} else if (sp->rxd_mode == RXD_MODE_3B) {
@@ -7400,13 +7404,13 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
unsigned char *buff = skb_push(skb, buf0_len);
struct buffAdd *ba = &ring_data->ba[get_block][get_off];
- sp->stats.rx_bytes += buf0_len + buf2_len;
+ ring_data->rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
skb_put(skb, buf2_len);
}
- if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
- (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
+ if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) ||
+ (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
(sp->rx_csum)) {
l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
@@ -7417,14 +7421,14 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
* a flag in the RxD.
*/
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (sp->lro) {
+ if (ring_data->lro) {
u32 tcp_len;
u8 *tcp;
int ret = 0;
- ret = s2io_club_tcp_session(skb->data, &tcp,
- &tcp_len, &lro,
- rxdp, sp);
+ ret = s2io_club_tcp_session(ring_data,
+ skb->data, &tcp, &tcp_len, &lro,
+ rxdp, sp);
switch (ret) {
case 3: /* Begin anew */
lro->parent = skb;
@@ -7486,7 +7490,7 @@ send_up:
queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
dev->last_rx = jiffies;
aggregate:
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ sp->mac_control.rings[ring_no].rx_bufs_left -= 1;
return SUCCESS;
}
@@ -7603,12 +7607,14 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
tx_steering_type = NO_STEERING;
}
- if ( rx_ring_num > 8) {
- DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
+ if (rx_ring_num > MAX_RX_RINGS) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested number of rx rings not "
"supported\n");
- DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
- rx_ring_num = 8;
+ DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n",
+ MAX_RX_RINGS);
+ rx_ring_num = MAX_RX_RINGS;
}
+
if (*dev_intr_type != INTA)
napi = 0;
@@ -7836,10 +7842,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Rx side parameters. */
config->rx_ring_num = rx_ring_num;
- for (i = 0; i < MAX_RX_RINGS; i++) {
+ for (i = 0; i < config->rx_ring_num; i++) {
config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
(rxd_count[sp->rxd_mode] + 1);
config->rx_cfg[i].ring_priority = i;
+ mac_control->rings[i].rx_bufs_left = 0;
+ mac_control->rings[i].rxd_mode = sp->rxd_mode;
+ mac_control->rings[i].rxd_count = rxd_count[sp->rxd_mode];
+ mac_control->rings[i].pdev = sp->pdev;
+ mac_control->rings[i].dev = sp->dev;
}
for (i = 0; i < rx_ring_num; i++) {
@@ -7854,10 +7865,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
- /* Initialize Ring buffer parameters. */
- for (i = 0; i < config->rx_ring_num; i++)
- atomic_set(&sp->rx_bufs_left[i], 0);
-
/* initialize the shared memory used by the NIC and the host */
if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
@@ -8077,6 +8084,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num);
+ DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name,
+ sp->config.rx_ring_num);
+
switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -8391,8 +8401,9 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
}
static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
- struct RxD_t *rxdp, struct s2io_nic *sp)
+s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp,
+ u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
+ struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@@ -8410,7 +8421,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &ring_data->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@@ -8448,7 +8459,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &ring_data->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index ce53a02105f2..0709ebae9139 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -678,11 +678,53 @@ struct rx_block_info {
struct rxd_info *rxds;
};
+/* Data structure to represent a LRO session */
+struct lro {
+ struct sk_buff *parent;
+ struct sk_buff *last_frag;
+ u8 *l2h;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ u32 tcp_next_seq;
+ __be32 tcp_ack;
+ int total_len;
+ int frags_len;
+ int sg_num;
+ int in_use;
+ __be16 window;
+ u16 vlan_tag;
+ u32 cur_tsval;
+ __be32 cur_tsecr;
+ u8 saw_ts;
+} ____cacheline_aligned;
+
/* Ring specific structure */
struct ring_info {
/* The ring number */
int ring_no;
+ /* per-ring buffer counter */
+ u32 rx_bufs_left;
+
+ #define MAX_LRO_SESSIONS 32
+ struct lro lro0_n[MAX_LRO_SESSIONS];
+ u8 lro;
+
+ /* copy of sp->rxd_mode flag */
+ int rxd_mode;
+
+ /* Number of rxds per block for the rxd_mode */
+ int rxd_count;
+
+ /* copy of sp pointer */
+ struct s2io_nic *nic;
+
+ /* copy of sp->dev pointer */
+ struct net_device *dev;
+
+ /* copy of sp->pdev pointer */
+ struct pci_dev *pdev;
+
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
@@ -703,10 +745,16 @@ struct ring_info {
*/
struct rx_curr_get_info rx_curr_get_info;
+ /* interface MTU value */
+ unsigned mtu;
+
/* Buffer Address store. */
struct buffAdd **ba;
- struct s2io_nic *nic;
-};
+
+ /* per-Ring statistics */
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+} ____cacheline_aligned;
/* Fifo specific structure */
struct fifo_info {
@@ -813,26 +861,6 @@ struct msix_info_st {
u64 data;
};
-/* Data structure to represent a LRO session */
-struct lro {
- struct sk_buff *parent;
- struct sk_buff *last_frag;
- u8 *l2h;
- struct iphdr *iph;
- struct tcphdr *tcph;
- u32 tcp_next_seq;
- __be32 tcp_ack;
- int total_len;
- int frags_len;
- int sg_num;
- int in_use;
- __be16 window;
- u16 vlan_tag;
- u32 cur_tsval;
- __be32 cur_tsecr;
- u8 saw_ts;
-} ____cacheline_aligned;
-
/* These flags represent the devices temporary state */
enum s2io_device_state_t
{
@@ -872,8 +900,6 @@ struct s2io_nic {
/* Space to back up the PCI config space */
u32 config_space[256 / sizeof(u32)];
- atomic_t rx_bufs_left[MAX_RX_RINGS];
-
#define PROMISC 1
#define ALL_MULTI 2
@@ -950,8 +976,6 @@ struct s2io_nic {
#define XFRAME_II_DEVICE 2
u8 device_type;
-#define MAX_LRO_SESSIONS 32
- struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@@ -1118,9 +1142,9 @@ static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr);
static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int offset);
static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr);
-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 int s2io_club_tcp_session(struct ring_info *ring_data, 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, u16 vlan_tag);
static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig
new file mode 100644
index 000000000000..dbad95c295bd
--- /dev/null
+++ b/drivers/net/sfc/Kconfig
@@ -0,0 +1,12 @@
+config SFC
+ tristate "Solarflare Solarstorm SFC4000 support"
+ depends on PCI && INET
+ select MII
+ select INET_LRO
+ select CRC32
+ help
+ This driver supports 10-gigabit Ethernet cards based on
+ the Solarflare Communications Solarstorm SFC4000 controller.
+
+ To compile this driver as a module, choose M here. The module
+ will be called sfc.
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
new file mode 100644
index 000000000000..1d2daeec7ac1
--- /dev/null
+++ b/drivers/net/sfc/Makefile
@@ -0,0 +1,5 @@
+sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
+ i2c-direct.o selftest.o ethtool.o xfp_phy.o \
+ mdio_10g.o tenxpress.o boards.o sfe4001.o
+
+obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h
new file mode 100644
index 000000000000..2806201644cc
--- /dev/null
+++ b/drivers/net/sfc/bitfield.h
@@ -0,0 +1,508 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_BITFIELD_H
+#define EFX_BITFIELD_H
+
+/*
+ * Efx bitfield access
+ *
+ * Efx NICs make extensive use of bitfields up to 128 bits
+ * wide. Since there is no native 128-bit datatype on most systems,
+ * and since 64-bit datatypes are inefficient on 32-bit systems and
+ * vice versa, we wrap accesses in a way that uses the most efficient
+ * datatype.
+ *
+ * The NICs are PCI devices and therefore little-endian. Since most
+ * of the quantities that we deal with are DMAed to/from host memory,
+ * we define our datatypes (efx_oword_t, efx_qword_t and
+ * efx_dword_t) to be little-endian.
+ */
+
+/* Lowest bit numbers and widths */
+#define EFX_DUMMY_FIELD_LBN 0
+#define EFX_DUMMY_FIELD_WIDTH 0
+#define EFX_DWORD_0_LBN 0
+#define EFX_DWORD_0_WIDTH 32
+#define EFX_DWORD_1_LBN 32
+#define EFX_DWORD_1_WIDTH 32
+#define EFX_DWORD_2_LBN 64
+#define EFX_DWORD_2_WIDTH 32
+#define EFX_DWORD_3_LBN 96
+#define EFX_DWORD_3_WIDTH 32
+
+/* Specified attribute (e.g. LBN) of the specified field */
+#define EFX_VAL(field, attribute) field ## _ ## attribute
+/* Low bit number of the specified field */
+#define EFX_LOW_BIT(field) EFX_VAL(field, LBN)
+/* Bit width of the specified field */
+#define EFX_WIDTH(field) EFX_VAL(field, WIDTH)
+/* High bit number of the specified field */
+#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1)
+/* Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 64 bits.
+ */
+#define EFX_MASK64(field) \
+ (EFX_WIDTH(field) == 64 ? ~((u64) 0) : \
+ (((((u64) 1) << EFX_WIDTH(field))) - 1))
+
+/* Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 32 bits. Use
+ * EFX_MASK64 for higher width fields.
+ */
+#define EFX_MASK32(field) \
+ (EFX_WIDTH(field) == 32 ? ~((u32) 0) : \
+ (((((u32) 1) << EFX_WIDTH(field))) - 1))
+
+/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
+typedef union efx_dword {
+ __le32 u32[1];
+} efx_dword_t;
+
+/* A quadword (i.e. 8 byte) datatype - little-endian in HW */
+typedef union efx_qword {
+ __le64 u64[1];
+ __le32 u32[2];
+ efx_dword_t dword[2];
+} efx_qword_t;
+
+/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */
+typedef union efx_oword {
+ __le64 u64[2];
+ efx_qword_t qword[2];
+ __le32 u32[4];
+ efx_dword_t dword[4];
+} efx_oword_t;
+
+/* Format string and value expanders for printk */
+#define EFX_DWORD_FMT "%08x"
+#define EFX_QWORD_FMT "%08x:%08x"
+#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x"
+#define EFX_DWORD_VAL(dword) \
+ ((unsigned int) le32_to_cpu((dword).u32[0]))
+#define EFX_QWORD_VAL(qword) \
+ ((unsigned int) le32_to_cpu((qword).u32[1])), \
+ ((unsigned int) le32_to_cpu((qword).u32[0]))
+#define EFX_OWORD_VAL(oword) \
+ ((unsigned int) le32_to_cpu((oword).u32[3])), \
+ ((unsigned int) le32_to_cpu((oword).u32[2])), \
+ ((unsigned int) le32_to_cpu((oword).u32[1])), \
+ ((unsigned int) le32_to_cpu((oword).u32[0]))
+
+/*
+ * Extract bit field portion [low,high) from the native-endian element
+ * which contains bits [min,max).
+ *
+ * For example, suppose "element" represents the high 32 bits of a
+ * 64-bit value, and we wish to extract the bits belonging to the bit
+ * field occupying bits 28-45 of this 64-bit value.
+ *
+ * Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give
+ *
+ * ( element ) << 4
+ *
+ * The result will contain the relevant bits filled in in the range
+ * [0,high-low), with garbage in bits [high-low+1,...).
+ */
+#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ ((native_element) >> (low - min)) : \
+ ((native_element) << (min - low))))
+
+/*
+ * Extract bit field portion [low,high) from the 64-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFX_EXTRACT64(element, min, max, low, high) \
+ EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high)
+
+/*
+ * Extract bit field portion [low,high) from the 32-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFX_EXTRACT32(element, min, max, low, high) \
+ EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
+
+#define EFX_EXTRACT_OWORD64(oword, low, high) \
+ (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \
+ EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
+
+#define EFX_EXTRACT_QWORD64(qword, low, high) \
+ EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
+
+#define EFX_EXTRACT_OWORD32(oword, low, high) \
+ (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \
+ EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \
+ EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \
+ EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
+
+#define EFX_EXTRACT_QWORD32(qword, low, high) \
+ (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \
+ EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
+
+#define EFX_EXTRACT_DWORD(dword, low, high) \
+ EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
+
+#define EFX_OWORD_FIELD64(oword, field) \
+ (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK64(field))
+
+#define EFX_QWORD_FIELD64(qword, field) \
+ (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK64(field))
+
+#define EFX_OWORD_FIELD32(oword, field) \
+ (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_QWORD_FIELD32(qword, field) \
+ (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_DWORD_FIELD(dword, field) \
+ (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_OWORD_IS_ZERO64(oword) \
+ (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
+
+#define EFX_QWORD_IS_ZERO64(qword) \
+ (((qword).u64[0]) == (__force __le64) 0)
+
+#define EFX_OWORD_IS_ZERO32(oword) \
+ (((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \
+ == (__force __le32) 0)
+
+#define EFX_QWORD_IS_ZERO32(qword) \
+ (((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0)
+
+#define EFX_DWORD_IS_ZERO(dword) \
+ (((dword).u32[0]) == (__force __le32) 0)
+
+#define EFX_OWORD_IS_ALL_ONES64(oword) \
+ (((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0))
+
+#define EFX_QWORD_IS_ALL_ONES64(qword) \
+ ((qword).u64[0] == ~((__force __le64) 0))
+
+#define EFX_OWORD_IS_ALL_ONES32(oword) \
+ (((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \
+ == ~((__force __le32) 0))
+
+#define EFX_QWORD_IS_ALL_ONES32(qword) \
+ (((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0))
+
+#define EFX_DWORD_IS_ALL_ONES(dword) \
+ ((dword).u32[0] == ~((__force __le32) 0))
+
+#if BITS_PER_LONG == 64
+#define EFX_OWORD_FIELD EFX_OWORD_FIELD64
+#define EFX_QWORD_FIELD EFX_QWORD_FIELD64
+#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO64
+#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO64
+#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64
+#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64
+#else
+#define EFX_OWORD_FIELD EFX_OWORD_FIELD32
+#define EFX_QWORD_FIELD EFX_QWORD_FIELD32
+#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO32
+#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO32
+#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32
+#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32
+#endif
+
+/*
+ * Construct bit field portion
+ *
+ * Creates the portion of the bit field [low,high) that lies within
+ * the range [min,max).
+ */
+#define EFX_INSERT_NATIVE64(min, max, low, high, value) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ (((u64) (value)) << (low - min)) : \
+ (((u64) (value)) >> (min - low))))
+
+#define EFX_INSERT_NATIVE32(min, max, low, high, value) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ (((u32) (value)) << (low - min)) : \
+ (((u32) (value)) >> (min - low))))
+
+#define EFX_INSERT_NATIVE(min, max, low, high, value) \
+ ((((max - min) >= 32) || ((high - low) >= 32)) ? \
+ EFX_INSERT_NATIVE64(min, max, low, high, value) : \
+ EFX_INSERT_NATIVE32(min, max, low, high, value))
+
+/*
+ * Construct bit field portion
+ *
+ * Creates the portion of the named bit field that lies within the
+ * range [min,max).
+ */
+#define EFX_INSERT_FIELD_NATIVE(min, max, field, value) \
+ EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field), \
+ EFX_HIGH_BIT(field), value)
+
+/*
+ * Construct bit field
+ *
+ * Creates the portion of the named bit fields that lie within the
+ * range [min,max).
+ */
+#define EFX_INSERT_FIELDS_NATIVE(min, max, \
+ field1, value1, \
+ field2, value2, \
+ field3, value3, \
+ field4, value4, \
+ field5, value5, \
+ field6, value6, \
+ field7, value7, \
+ field8, value8, \
+ field9, value9, \
+ field10, value10) \
+ (EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)))
+
+#define EFX_INSERT_FIELDS64(...) \
+ cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
+
+#define EFX_INSERT_FIELDS32(...) \
+ cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
+
+#define EFX_POPULATE_OWORD64(oword, ...) do { \
+ (oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
+ (oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_QWORD64(qword, ...) do { \
+ (qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_OWORD32(oword, ...) do { \
+ (oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ (oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
+ (oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__); \
+ (oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_QWORD32(qword, ...) do { \
+ (qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ (qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_DWORD(dword, ...) do { \
+ (dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ } while (0)
+
+#if BITS_PER_LONG == 64
+#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
+#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
+#else
+#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
+#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
+#endif
+
+/* Populate an octword field with various numbers of arguments */
+#define EFX_POPULATE_OWORD_10 EFX_POPULATE_OWORD
+#define EFX_POPULATE_OWORD_9(oword, ...) \
+ EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_8(oword, ...) \
+ EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_7(oword, ...) \
+ EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_6(oword, ...) \
+ EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_5(oword, ...) \
+ EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_4(oword, ...) \
+ EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_3(oword, ...) \
+ EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_2(oword, ...) \
+ EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_1(oword, ...) \
+ EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_OWORD(oword) \
+ EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_OWORD(oword) \
+ EFX_POPULATE_OWORD_4(oword, \
+ EFX_DWORD_0, 0xffffffff, \
+ EFX_DWORD_1, 0xffffffff, \
+ EFX_DWORD_2, 0xffffffff, \
+ EFX_DWORD_3, 0xffffffff)
+
+/* Populate a quadword field with various numbers of arguments */
+#define EFX_POPULATE_QWORD_10 EFX_POPULATE_QWORD
+#define EFX_POPULATE_QWORD_9(qword, ...) \
+ EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_8(qword, ...) \
+ EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_7(qword, ...) \
+ EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_6(qword, ...) \
+ EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_5(qword, ...) \
+ EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_4(qword, ...) \
+ EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_3(qword, ...) \
+ EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_2(qword, ...) \
+ EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_1(qword, ...) \
+ EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_QWORD(qword) \
+ EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_QWORD(qword) \
+ EFX_POPULATE_QWORD_2(qword, \
+ EFX_DWORD_0, 0xffffffff, \
+ EFX_DWORD_1, 0xffffffff)
+
+/* Populate a dword field with various numbers of arguments */
+#define EFX_POPULATE_DWORD_10 EFX_POPULATE_DWORD
+#define EFX_POPULATE_DWORD_9(dword, ...) \
+ EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_8(dword, ...) \
+ EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_7(dword, ...) \
+ EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_6(dword, ...) \
+ EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_5(dword, ...) \
+ EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_4(dword, ...) \
+ EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_3(dword, ...) \
+ EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_2(dword, ...) \
+ EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_1(dword, ...) \
+ EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_DWORD(dword) \
+ EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_DWORD(dword) \
+ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff)
+
+/*
+ * Modify a named field within an already-populated structure. Used
+ * for read-modify-write operations.
+ *
+ */
+
+#define EFX_INVERT_OWORD(oword) do { \
+ (oword).u64[0] = ~((oword).u64[0]); \
+ (oword).u64[1] = ~((oword).u64[1]); \
+ } while (0)
+
+#define EFX_INSERT_FIELD64(...) \
+ cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+
+#define EFX_INSERT_FIELD32(...) \
+ cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+
+#define EFX_INPLACE_MASK64(min, max, field) \
+ EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
+
+#define EFX_INPLACE_MASK32(min, max, field) \
+ EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
+
+#define EFX_SET_OWORD_FIELD64(oword, field, value) do { \
+ (oword).u64[0] = (((oword).u64[0] \
+ & ~EFX_INPLACE_MASK64(0, 63, field)) \
+ | EFX_INSERT_FIELD64(0, 63, field, value)); \
+ (oword).u64[1] = (((oword).u64[1] \
+ & ~EFX_INPLACE_MASK64(64, 127, field)) \
+ | EFX_INSERT_FIELD64(64, 127, field, value)); \
+ } while (0)
+
+#define EFX_SET_QWORD_FIELD64(qword, field, value) do { \
+ (qword).u64[0] = (((qword).u64[0] \
+ & ~EFX_INPLACE_MASK64(0, 63, field)) \
+ | EFX_INSERT_FIELD64(0, 63, field, value)); \
+ } while (0)
+
+#define EFX_SET_OWORD_FIELD32(oword, field, value) do { \
+ (oword).u32[0] = (((oword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ (oword).u32[1] = (((oword).u32[1] \
+ & ~EFX_INPLACE_MASK32(32, 63, field)) \
+ | EFX_INSERT_FIELD32(32, 63, field, value)); \
+ (oword).u32[2] = (((oword).u32[2] \
+ & ~EFX_INPLACE_MASK32(64, 95, field)) \
+ | EFX_INSERT_FIELD32(64, 95, field, value)); \
+ (oword).u32[3] = (((oword).u32[3] \
+ & ~EFX_INPLACE_MASK32(96, 127, field)) \
+ | EFX_INSERT_FIELD32(96, 127, field, value)); \
+ } while (0)
+
+#define EFX_SET_QWORD_FIELD32(qword, field, value) do { \
+ (qword).u32[0] = (((qword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ (qword).u32[1] = (((qword).u32[1] \
+ & ~EFX_INPLACE_MASK32(32, 63, field)) \
+ | EFX_INSERT_FIELD32(32, 63, field, value)); \
+ } while (0)
+
+#define EFX_SET_DWORD_FIELD(dword, field, value) do { \
+ (dword).u32[0] = (((dword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ } while (0)
+
+#if BITS_PER_LONG == 64
+#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
+#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
+#else
+#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
+#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
+#endif
+
+#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
+ if (FALCON_REV(efx) >= FALCON_REV_B0) { \
+ EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
+ } else { \
+ EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
+ } \
+} while (0)
+
+#define EFX_QWORD_FIELD_VER(efx, qword, field) \
+ (FALCON_REV(efx) >= FALCON_REV_B0 ? \
+ EFX_QWORD_FIELD((qword), field##_B0) : \
+ EFX_QWORD_FIELD((qword), field##_A1))
+
+/* Used to avoid compiler warnings about shift range exceeding width
+ * of the data types when dma_addr_t is only 32 bits wide.
+ */
+#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t))
+#define EFX_DMA_TYPE_WIDTH(width) \
+ (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
+#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
+ ~((u64) 0) : ~((u32) 0))
+#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
+
+#endif /* EFX_BITFIELD_H */
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
new file mode 100644
index 000000000000..eecaa6d58584
--- /dev/null
+++ b/drivers/net/sfc/boards.c
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include "net_driver.h"
+#include "phy.h"
+#include "boards.h"
+#include "efx.h"
+
+/* Macros for unpacking the board revision */
+/* The revision info is in host byte order. */
+#define BOARD_TYPE(_rev) (_rev >> 8)
+#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
+#define BOARD_MINOR(_rev) (_rev & 0xf)
+
+/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
+#define BLINK_INTERVAL (HZ/2)
+
+static void blink_led_timer(unsigned long context)
+{
+ struct efx_nic *efx = (struct efx_nic *)context;
+ struct efx_blinker *bl = &efx->board_info.blinker;
+ efx->board_info.set_fault_led(efx, bl->state);
+ bl->state = !bl->state;
+ if (bl->resubmit) {
+ bl->timer.expires = jiffies + BLINK_INTERVAL;
+ add_timer(&bl->timer);
+ }
+}
+
+static void board_blink(struct efx_nic *efx, int blink)
+{
+ struct efx_blinker *blinker = &efx->board_info.blinker;
+
+ /* The rtnl mutex serialises all ethtool ioctls, so
+ * nothing special needs doing here. */
+ if (blink) {
+ blinker->resubmit = 1;
+ blinker->state = 0;
+ setup_timer(&blinker->timer, blink_led_timer,
+ (unsigned long)efx);
+ blinker->timer.expires = jiffies + BLINK_INTERVAL;
+ add_timer(&blinker->timer);
+ } else {
+ blinker->resubmit = 0;
+ if (blinker->timer.function)
+ del_timer_sync(&blinker->timer);
+ efx->board_info.set_fault_led(efx, 0);
+ }
+}
+
+/*****************************************************************************
+ * Support for the SFE4002
+ *
+ */
+/****************************************************************************/
+/* LED allocations. Note that on rev A0 boards the schematic and the reality
+ * differ: red and green are swapped. Below is the fixed (A1) layout (there
+ * are only 3 A0 boards in existence, so no real reason to make this
+ * conditional).
+ */
+#define SFE4002_FAULT_LED (2) /* Red */
+#define SFE4002_RX_LED (0) /* Green */
+#define SFE4002_TX_LED (1) /* Amber */
+
+static int sfe4002_init_leds(struct efx_nic *efx)
+{
+ /* Set the TX and RX LEDs to reflect status and activity, and the
+ * fault LED off */
+ xfp_set_led(efx, SFE4002_TX_LED,
+ QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
+ xfp_set_led(efx, SFE4002_RX_LED,
+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
+ xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
+ efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
+ return 0;
+}
+
+static void sfe4002_fault_led(struct efx_nic *efx, int state)
+{
+ xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
+ QUAKE_LED_OFF);
+}
+
+static int sfe4002_init(struct efx_nic *efx)
+{
+ efx->board_info.init_leds = sfe4002_init_leds;
+ efx->board_info.set_fault_led = sfe4002_fault_led;
+ efx->board_info.blink = board_blink;
+ return 0;
+}
+
+/* This will get expanded as board-specific details get moved out of the
+ * PHY drivers. */
+struct efx_board_data {
+ const char *ref_model;
+ const char *gen_type;
+ int (*init) (struct efx_nic *nic);
+};
+
+static int dummy_init(struct efx_nic *nic)
+{
+ return 0;
+}
+
+static struct efx_board_data board_data[] = {
+ [EFX_BOARD_INVALID] =
+ {NULL, NULL, dummy_init},
+ [EFX_BOARD_SFE4001] =
+ {"SFE4001", "10GBASE-T adapter", sfe4001_poweron},
+ [EFX_BOARD_SFE4002] =
+ {"SFE4002", "XFP adapter", sfe4002_init},
+};
+
+int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
+{
+ int rc = 0;
+ struct efx_board_data *data;
+
+ if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
+ EFX_ERR(efx, "squashing unknown board type %d\n",
+ BOARD_TYPE(revision_info));
+ revision_info = 0;
+ }
+
+ if (BOARD_TYPE(revision_info) == 0) {
+ efx->board_info.major = 0;
+ efx->board_info.minor = 0;
+ /* For early boards that don't have revision info. there is
+ * only 1 board for each PHY type, so we can work it out, with
+ * the exception of the PHY-less boards. */
+ switch (efx->phy_type) {
+ case PHY_TYPE_10XPRESS:
+ efx->board_info.type = EFX_BOARD_SFE4001;
+ break;
+ case PHY_TYPE_XFP:
+ efx->board_info.type = EFX_BOARD_SFE4002;
+ break;
+ default:
+ efx->board_info.type = 0;
+ break;
+ }
+ } else {
+ efx->board_info.type = BOARD_TYPE(revision_info);
+ efx->board_info.major = BOARD_MAJOR(revision_info);
+ efx->board_info.minor = BOARD_MINOR(revision_info);
+ }
+
+ data = &board_data[efx->board_info.type];
+
+ /* Report the board model number or generic type for recognisable
+ * boards. */
+ if (efx->board_info.type != 0)
+ EFX_INFO(efx, "board is %s rev %c%d\n",
+ (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
+ ? data->ref_model : data->gen_type,
+ 'A' + efx->board_info.major, efx->board_info.minor);
+
+ efx->board_info.init = data->init;
+
+ return rc;
+}
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
new file mode 100644
index 000000000000..695764dc2e64
--- /dev/null
+++ b/drivers/net/sfc/boards.h
@@ -0,0 +1,28 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_BOARDS_H
+#define EFX_BOARDS_H
+
+/* Board IDs (must fit in 8 bits) */
+enum efx_board_type {
+ EFX_BOARD_INVALID = 0,
+ EFX_BOARD_SFE4001 = 1, /* SFE4001 (10GBASE-T) */
+ EFX_BOARD_SFE4002 = 2,
+ /* Insert new types before here */
+ EFX_BOARD_MAX
+};
+
+extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
+extern int sfe4001_poweron(struct efx_nic *efx);
+extern void sfe4001_poweroff(struct efx_nic *efx);
+/* Are we putting the PHY into flash config mode */
+extern unsigned int sfe4001_phy_flash_cfg;
+
+#endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
new file mode 100644
index 000000000000..418f2e53a95b
--- /dev/null
+++ b/drivers/net/sfc/efx.c
@@ -0,0 +1,2210 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include "net_driver.h"
+#include "gmii.h"
+#include "ethtool.h"
+#include "tx.h"
+#include "rx.h"
+#include "efx.h"
+#include "mdio_10g.h"
+#include "falcon.h"
+#include "workarounds.h"
+#include "mac.h"
+
+#define EFX_MAX_MTU (9 * 1024)
+
+/* RX slow fill workqueue. If memory allocation fails in the fast path,
+ * a work item is pushed onto this work queue to retry the allocation later,
+ * to avoid the NIC being starved of RX buffers. Since this is a per cpu
+ * workqueue, there is nothing to be gained in making it per NIC
+ */
+static struct workqueue_struct *refill_workqueue;
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ *************************************************************************/
+
+/*
+ * Enable large receive offload (LRO) aka soft segment reassembly (SSR)
+ *
+ * This sets the default for new devices. It can be controlled later
+ * using ethtool.
+ */
+static int lro = 1;
+module_param(lro, int, 0644);
+MODULE_PARM_DESC(lro, "Large receive offload acceleration");
+
+/*
+ * Use separate channels for TX and RX events
+ *
+ * Set this to 1 to use separate channels for TX and RX. It allows us to
+ * apply a higher level of interrupt moderation to TX events.
+ *
+ * This is forced to 0 for MSI interrupt mode as the interrupt vector
+ * is not written
+ */
+static unsigned int separate_tx_and_rx_channels = 1;
+
+/* This is the weight assigned to each of the (per-channel) virtual
+ * NAPI devices.
+ */
+static int napi_weight = 64;
+
+/* This is the time (in jiffies) between invocations of the hardware
+ * monitor, which checks for known hardware bugs and resets the
+ * hardware and driver as necessary.
+ */
+unsigned int efx_monitor_interval = 1 * HZ;
+
+/* This controls whether or not the hardware monitor will trigger a
+ * reset when it detects an error condition.
+ */
+static unsigned int monitor_reset = 1;
+
+/* This controls whether or not the driver will initialise devices
+ * with invalid MAC addresses stored in the EEPROM or flash. If true,
+ * such devices will be initialised with a random locally-generated
+ * MAC address. This allows for loading the sfc_mtd driver to
+ * reprogram the flash, even if the flash contents (including the MAC
+ * address) have previously been erased.
+ */
+static unsigned int allow_bad_hwaddr;
+
+/* Initial interrupt moderation settings. They can be modified after
+ * module load with ethtool.
+ *
+ * The default for RX should strike a balance between increasing the
+ * round-trip latency and reducing overhead.
+ */
+static unsigned int rx_irq_mod_usec = 60;
+
+/* Initial interrupt moderation settings. They can be modified after
+ * module load with ethtool.
+ *
+ * This default is chosen to ensure that a 10G link does not go idle
+ * while a TX queue is stopped after it has become full. A queue is
+ * restarted when it drops below half full. The time this takes (assuming
+ * worst case 3 descriptors per packet and 1024 descriptors) is
+ * 512 / 3 * 1.2 = 205 usec.
+ */
+static unsigned int tx_irq_mod_usec = 150;
+
+/* This is the first interrupt mode to try out of:
+ * 0 => MSI-X
+ * 1 => MSI
+ * 2 => legacy
+ */
+static unsigned int interrupt_mode;
+
+/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
+ * i.e. the number of CPUs among which we may distribute simultaneous
+ * interrupt handling.
+ *
+ * Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
+ * The default (0) means to assign an interrupt to each package (level II cache)
+ */
+static unsigned int rss_cpus;
+module_param(rss_cpus, uint, 0444);
+MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
+
+/**************************************************************************
+ *
+ * Utility functions and prototypes
+ *
+ *************************************************************************/
+static void efx_remove_channel(struct efx_channel *channel);
+static void efx_remove_port(struct efx_nic *efx);
+static void efx_fini_napi(struct efx_nic *efx);
+static void efx_fini_channels(struct efx_nic *efx);
+
+#define EFX_ASSERT_RESET_SERIALISED(efx) \
+ do { \
+ if ((efx->state == STATE_RUNNING) || \
+ (efx->state == STATE_RESETTING)) \
+ ASSERT_RTNL(); \
+ } while (0)
+
+/**************************************************************************
+ *
+ * Event queue processing
+ *
+ *************************************************************************/
+
+/* Process channel's event queue
+ *
+ * This function is responsible for processing the event queue of a
+ * single channel. The caller must guarantee that this function will
+ * never be concurrently called more than once on the same channel,
+ * though different channels may be being processed concurrently.
+ */
+static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
+{
+ int rxdmaqs;
+ struct efx_rx_queue *rx_queue;
+
+ if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
+ !channel->enabled))
+ return rx_quota;
+
+ rxdmaqs = falcon_process_eventq(channel, &rx_quota);
+
+ /* Deliver last RX packet. */
+ if (channel->rx_pkt) {
+ __efx_rx_packet(channel, channel->rx_pkt,
+ channel->rx_pkt_csummed);
+ channel->rx_pkt = NULL;
+ }
+
+ efx_flush_lro(channel);
+ efx_rx_strategy(channel);
+
+ /* Refill descriptor rings as necessary */
+ rx_queue = &channel->efx->rx_queue[0];
+ while (rxdmaqs) {
+ if (rxdmaqs & 0x01)
+ efx_fast_push_rx_descriptors(rx_queue);
+ rx_queue++;
+ rxdmaqs >>= 1;
+ }
+
+ return rx_quota;
+}
+
+/* Mark channel as finished processing
+ *
+ * Note that since we will not receive further interrupts for this
+ * channel before we finish processing and call the eventq_read_ack()
+ * method, there is no need to use the interrupt hold-off timers.
+ */
+static inline void efx_channel_processed(struct efx_channel *channel)
+{
+ /* Write to EVQ_RPTR_REG. If a new event arrived in a race
+ * with finishing processing, a new interrupt will be raised.
+ */
+ channel->work_pending = 0;
+ smp_wmb(); /* Ensure channel updated before any new interrupt. */
+ falcon_eventq_read_ack(channel);
+}
+
+/* NAPI poll handler
+ *
+ * NAPI guarantees serialisation of polls of the same device, which
+ * provides the guarantee required by efx_process_channel().
+ */
+static int efx_poll(struct napi_struct *napi, int budget)
+{
+ struct efx_channel *channel =
+ container_of(napi, struct efx_channel, napi_str);
+ struct net_device *napi_dev = channel->napi_dev;
+ int unused;
+ int rx_packets;
+
+ EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
+ channel->channel, raw_smp_processor_id());
+
+ unused = efx_process_channel(channel, budget);
+ rx_packets = (budget - unused);
+
+ if (rx_packets < budget) {
+ /* There is no race here; although napi_disable() will
+ * only wait for netif_rx_complete(), this isn't a problem
+ * since efx_channel_processed() will have no effect if
+ * interrupts have already been disabled.
+ */
+ netif_rx_complete(napi_dev, napi);
+ efx_channel_processed(channel);
+ }
+
+ return rx_packets;
+}
+
+/* Process the eventq of the specified channel immediately on this CPU
+ *
+ * Disable hardware generated interrupts, wait for any existing
+ * processing to finish, then directly poll (and ack ) the eventq.
+ * Finally reenable NAPI and interrupts.
+ *
+ * Since we are touching interrupts the caller should hold the suspend lock
+ */
+void efx_process_channel_now(struct efx_channel *channel)
+{
+ struct efx_nic *efx = channel->efx;
+
+ BUG_ON(!channel->used_flags);
+ BUG_ON(!channel->enabled);
+
+ /* Disable interrupts and wait for ISRs to complete */
+ falcon_disable_interrupts(efx);
+ if (efx->legacy_irq)
+ synchronize_irq(efx->legacy_irq);
+ if (channel->has_interrupt && channel->irq)
+ synchronize_irq(channel->irq);
+
+ /* Wait for any NAPI processing to complete */
+ napi_disable(&channel->napi_str);
+
+ /* Poll the channel */
+ (void) efx_process_channel(channel, efx->type->evq_size);
+
+ /* Ack the eventq. This may cause an interrupt to be generated
+ * when they are reenabled */
+ efx_channel_processed(channel);
+
+ napi_enable(&channel->napi_str);
+ falcon_enable_interrupts(efx);
+}
+
+/* Create event queue
+ * Event queue memory allocations are done only once. If the channel
+ * is reset, the memory buffer will be reused; this guards against
+ * errors during channel reset and also simplifies interrupt handling.
+ */
+static int efx_probe_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
+
+ return falcon_probe_eventq(channel);
+}
+
+/* Prepare channel's event queue */
+static int efx_init_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
+
+ channel->eventq_read_ptr = 0;
+
+ return falcon_init_eventq(channel);
+}
+
+static void efx_fini_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
+
+ falcon_fini_eventq(channel);
+}
+
+static void efx_remove_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
+
+ falcon_remove_eventq(channel);
+}
+
+/**************************************************************************
+ *
+ * Channel handling
+ *
+ *************************************************************************/
+
+/* Setup per-NIC RX buffer parameters.
+ * Calculate the rx buffer allocation parameters required to support
+ * the current MTU, including padding for header alignment and overruns.
+ */
+static void efx_calc_rx_buffer_params(struct efx_nic *efx)
+{
+ unsigned int order, len;
+
+ len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
+ EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+ efx->type->rx_buffer_padding);
+
+ /* Calculate page-order */
+ for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order)
+ ;
+
+ efx->rx_buffer_len = len;
+ efx->rx_buffer_order = order;
+}
+
+static int efx_probe_channel(struct efx_channel *channel)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int rc;
+
+ EFX_LOG(channel->efx, "creating channel %d\n", channel->channel);
+
+ rc = efx_probe_eventq(channel);
+ if (rc)
+ goto fail1;
+
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ rc = efx_probe_tx_queue(tx_queue);
+ if (rc)
+ goto fail2;
+ }
+
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ rc = efx_probe_rx_queue(rx_queue);
+ if (rc)
+ goto fail3;
+ }
+
+ channel->n_rx_frm_trunc = 0;
+
+ return 0;
+
+ fail3:
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_remove_rx_queue(rx_queue);
+ fail2:
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_remove_tx_queue(tx_queue);
+ fail1:
+ return rc;
+}
+
+
+/* Channels are shutdown and reinitialised whilst the NIC is running
+ * to propagate configuration changes (mtu, checksum offload), or
+ * to clear hardware error conditions
+ */
+static int efx_init_channels(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+ int rc = 0;
+
+ efx_calc_rx_buffer_params(efx);
+
+ /* Initialise the channels */
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
+
+ rc = efx_init_eventq(channel);
+ if (rc)
+ goto err;
+
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ rc = efx_init_tx_queue(tx_queue);
+ if (rc)
+ goto err;
+ }
+
+ /* The rx buffer allocation strategy is MTU dependent */
+ efx_rx_strategy(channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ rc = efx_init_rx_queue(rx_queue);
+ if (rc)
+ goto err;
+ }
+
+ WARN_ON(channel->rx_pkt != NULL);
+ efx_rx_strategy(channel);
+ }
+
+ return 0;
+
+ err:
+ EFX_ERR(efx, "failed to initialise channel %d\n",
+ channel ? channel->channel : -1);
+ efx_fini_channels(efx);
+ return rc;
+}
+
+/* This enables event queue processing and packet transmission.
+ *
+ * Note that this function is not allowed to fail, since that would
+ * introduce too much complexity into the suspend/resume path.
+ */
+static void efx_start_channel(struct efx_channel *channel)
+{
+ struct efx_rx_queue *rx_queue;
+
+ EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
+
+ if (!(channel->efx->net_dev->flags & IFF_UP))
+ netif_napi_add(channel->napi_dev, &channel->napi_str,
+ efx_poll, napi_weight);
+
+ channel->work_pending = 0;
+ channel->enabled = 1;
+ smp_wmb(); /* ensure channel updated before first interrupt */
+
+ napi_enable(&channel->napi_str);
+
+ /* Load up RX descriptors */
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_fast_push_rx_descriptors(rx_queue);
+}
+
+/* This disables event queue processing and packet transmission.
+ * This function does not guarantee that all queue processing
+ * (e.g. RX refill) is complete.
+ */
+static void efx_stop_channel(struct efx_channel *channel)
+{
+ struct efx_rx_queue *rx_queue;
+
+ if (!channel->enabled)
+ return;
+
+ EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
+
+ channel->enabled = 0;
+ napi_disable(&channel->napi_str);
+
+ /* Ensure that any worker threads have exited or will be no-ops */
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ spin_lock_bh(&rx_queue->add_lock);
+ spin_unlock_bh(&rx_queue->add_lock);
+ }
+}
+
+static void efx_fini_channels(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+ BUG_ON(efx->port_enabled);
+
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_fini_rx_queue(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_fini_tx_queue(tx_queue);
+ }
+
+ /* Do the event queues last so that we can handle flush events
+ * for all DMA queues. */
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel);
+
+ efx_fini_eventq(channel);
+ }
+}
+
+static void efx_remove_channel(struct efx_channel *channel)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_remove_rx_queue(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_remove_tx_queue(tx_queue);
+ efx_remove_eventq(channel);
+
+ channel->used_flags = 0;
+}
+
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+{
+ queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+}
+
+/**************************************************************************
+ *
+ * Port handling
+ *
+ **************************************************************************/
+
+/* This ensures that the kernel is kept informed (via
+ * netif_carrier_on/off) of the link status, and also maintains the
+ * link status's stop on the port's TX queue.
+ */
+static void efx_link_status_changed(struct efx_nic *efx)
+{
+ int carrier_ok;
+
+ /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
+ * that no events are triggered between unregister_netdev() and the
+ * driver unloading. A more general condition is that NETDEV_CHANGE
+ * can only be generated between NETDEV_UP and NETDEV_DOWN */
+ if (!netif_running(efx->net_dev))
+ return;
+
+ carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0;
+ if (efx->link_up != carrier_ok) {
+ efx->n_link_state_changes++;
+
+ if (efx->link_up)
+ netif_carrier_on(efx->net_dev);
+ else
+ netif_carrier_off(efx->net_dev);
+ }
+
+ /* Status message for kernel log */
+ if (efx->link_up) {
+ struct mii_if_info *gmii = &efx->mii;
+ unsigned adv, lpa;
+ /* NONE here means direct XAUI from the controller, with no
+ * MDIO-attached device we can query. */
+ if (efx->phy_type != PHY_TYPE_NONE) {
+ adv = gmii_advertised(gmii);
+ lpa = gmii_lpa(gmii);
+ } else {
+ lpa = GM_LPA_10000 | LPA_DUPLEX;
+ adv = lpa;
+ }
+ EFX_INFO(efx, "link up at %dMbps %s-duplex "
+ "(adv %04x lpa %04x) (MTU %d)%s\n",
+ (efx->link_options & GM_LPA_10000 ? 10000 :
+ (efx->link_options & GM_LPA_1000 ? 1000 :
+ (efx->link_options & GM_LPA_100 ? 100 :
+ 10))),
+ (efx->link_options & GM_LPA_DUPLEX ?
+ "full" : "half"),
+ adv, lpa,
+ efx->net_dev->mtu,
+ (efx->promiscuous ? " [PROMISC]" : ""));
+ } else {
+ EFX_INFO(efx, "link down\n");
+ }
+
+}
+
+/* This call reinitialises the MAC to pick up new PHY settings. The
+ * caller must hold the mac_lock */
+static void __efx_reconfigure_port(struct efx_nic *efx)
+{
+ WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+ EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
+ raw_smp_processor_id());
+
+ falcon_reconfigure_xmac(efx);
+
+ /* Inform kernel of loss/gain of carrier */
+ efx_link_status_changed(efx);
+}
+
+/* Reinitialise the MAC to pick up new PHY settings, even if the port is
+ * disabled. */
+void efx_reconfigure_port(struct efx_nic *efx)
+{
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ mutex_lock(&efx->mac_lock);
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all()
+ * we don't efx_reconfigure_port() if the port is disabled. Care is taken
+ * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */
+static void efx_reconfigure_work(struct work_struct *data)
+{
+ struct efx_nic *efx = container_of(data, struct efx_nic,
+ reconfigure_work);
+
+ mutex_lock(&efx->mac_lock);
+ if (efx->port_enabled)
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+static int efx_probe_port(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "create port\n");
+
+ /* Connect up MAC/PHY operations table and read MAC address */
+ rc = falcon_probe_port(efx);
+ if (rc)
+ goto err;
+
+ /* Sanity check MAC address */
+ if (is_valid_ether_addr(efx->mac_address)) {
+ memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
+ } else {
+ DECLARE_MAC_BUF(mac);
+
+ EFX_ERR(efx, "invalid MAC address %s\n",
+ print_mac(mac, efx->mac_address));
+ if (!allow_bad_hwaddr) {
+ rc = -EINVAL;
+ goto err;
+ }
+ random_ether_addr(efx->net_dev->dev_addr);
+ EFX_INFO(efx, "using locally-generated MAC %s\n",
+ print_mac(mac, efx->net_dev->dev_addr));
+ }
+
+ return 0;
+
+ err:
+ efx_remove_port(efx);
+ return rc;
+}
+
+static int efx_init_port(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "init port\n");
+
+ /* Initialise the MAC and PHY */
+ rc = falcon_init_xmac(efx);
+ if (rc)
+ return rc;
+
+ efx->port_initialized = 1;
+
+ /* Reconfigure port to program MAC registers */
+ falcon_reconfigure_xmac(efx);
+
+ return 0;
+}
+
+/* Allow efx_reconfigure_port() to be scheduled, and close the window
+ * between efx_stop_port and efx_flush_all whereby a previously scheduled
+ * efx_reconfigure_port() may have been cancelled */
+static void efx_start_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "start port\n");
+ BUG_ON(efx->port_enabled);
+
+ mutex_lock(&efx->mac_lock);
+ efx->port_enabled = 1;
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+/* Prevent efx_reconfigure_work and efx_monitor() from executing, and
+ * efx_set_multicast_list() from scheduling efx_reconfigure_work.
+ * efx_reconfigure_work can still be scheduled via NAPI processing
+ * until efx_flush_all() is called */
+static void efx_stop_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "stop port\n");
+
+ mutex_lock(&efx->mac_lock);
+ efx->port_enabled = 0;
+ mutex_unlock(&efx->mac_lock);
+
+ /* Serialise against efx_set_multicast_list() */
+ if (NET_DEV_REGISTERED(efx)) {
+ netif_tx_lock_bh(efx->net_dev);
+ netif_tx_unlock_bh(efx->net_dev);
+ }
+}
+
+static void efx_fini_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "shut down port\n");
+
+ if (!efx->port_initialized)
+ return;
+
+ falcon_fini_xmac(efx);
+ efx->port_initialized = 0;
+
+ efx->link_up = 0;
+ efx_link_status_changed(efx);
+}
+
+static void efx_remove_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "destroying port\n");
+
+ falcon_remove_port(efx);
+}
+
+/**************************************************************************
+ *
+ * NIC handling
+ *
+ **************************************************************************/
+
+/* This configures the PCI device to enable I/O and DMA. */
+static int efx_init_io(struct efx_nic *efx)
+{
+ struct pci_dev *pci_dev = efx->pci_dev;
+ dma_addr_t dma_mask = efx->type->max_dma_mask;
+ int rc;
+
+ EFX_LOG(efx, "initialising I/O\n");
+
+ rc = pci_enable_device(pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to enable PCI device\n");
+ goto fail1;
+ }
+
+ pci_set_master(pci_dev);
+
+ /* Set the PCI DMA mask. Try all possibilities from our
+ * genuine mask down to 32 bits, because some architectures
+ * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit
+ * masks event though they reject 46 bit masks.
+ */
+ while (dma_mask > 0x7fffffffUL) {
+ if (pci_dma_supported(pci_dev, dma_mask) &&
+ ((rc = pci_set_dma_mask(pci_dev, dma_mask)) == 0))
+ break;
+ dma_mask >>= 1;
+ }
+ if (rc) {
+ EFX_ERR(efx, "could not find a suitable DMA mask\n");
+ goto fail2;
+ }
+ EFX_LOG(efx, "using DMA mask %llx\n", (unsigned long long) dma_mask);
+ rc = pci_set_consistent_dma_mask(pci_dev, dma_mask);
+ if (rc) {
+ /* pci_set_consistent_dma_mask() is not *allowed* to
+ * fail with a mask that pci_set_dma_mask() accepted,
+ * but just in case...
+ */
+ EFX_ERR(efx, "failed to set consistent DMA mask\n");
+ goto fail2;
+ }
+
+ efx->membase_phys = pci_resource_start(efx->pci_dev,
+ efx->type->mem_bar);
+ rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc");
+ if (rc) {
+ EFX_ERR(efx, "request for memory BAR failed\n");
+ rc = -EIO;
+ goto fail3;
+ }
+ efx->membase = ioremap_nocache(efx->membase_phys,
+ efx->type->mem_map_size);
+ if (!efx->membase) {
+ EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n",
+ efx->type->mem_bar, efx->membase_phys,
+ efx->type->mem_map_size);
+ rc = -ENOMEM;
+ goto fail4;
+ }
+ EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n",
+ efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size,
+ efx->membase);
+
+ return 0;
+
+ fail4:
+ release_mem_region(efx->membase_phys, efx->type->mem_map_size);
+ fail3:
+ efx->membase_phys = 0UL;
+ fail2:
+ pci_disable_device(efx->pci_dev);
+ fail1:
+ return rc;
+}
+
+static void efx_fini_io(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "shutting down I/O\n");
+
+ if (efx->membase) {
+ iounmap(efx->membase);
+ efx->membase = NULL;
+ }
+
+ if (efx->membase_phys) {
+ pci_release_region(efx->pci_dev, efx->type->mem_bar);
+ efx->membase_phys = 0UL;
+ }
+
+ pci_disable_device(efx->pci_dev);
+}
+
+/* Probe the number and type of interrupts we are able to obtain. */
+static void efx_probe_interrupts(struct efx_nic *efx)
+{
+ int max_channel = efx->type->phys_addr_channels - 1;
+ struct msix_entry xentries[EFX_MAX_CHANNELS];
+ int rc, i;
+
+ if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
+ BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
+
+ efx->rss_queues = rss_cpus ? rss_cpus : num_online_cpus();
+ efx->rss_queues = min(efx->rss_queues, max_channel + 1);
+ efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
+
+ /* Request maximum number of MSI interrupts, and fill out
+ * the channel interrupt information the allowed allocation */
+ for (i = 0; i < efx->rss_queues; i++)
+ xentries[i].entry = i;
+ rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
+ if (rc > 0) {
+ EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
+ efx->rss_queues = rc;
+ rc = pci_enable_msix(efx->pci_dev, xentries,
+ efx->rss_queues);
+ }
+
+ if (rc == 0) {
+ for (i = 0; i < efx->rss_queues; i++) {
+ efx->channel[i].has_interrupt = 1;
+ efx->channel[i].irq = xentries[i].vector;
+ }
+ } else {
+ /* Fall back to single channel MSI */
+ efx->interrupt_mode = EFX_INT_MODE_MSI;
+ EFX_ERR(efx, "could not enable MSI-X\n");
+ }
+ }
+
+ /* Try single interrupt MSI */
+ if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
+ efx->rss_queues = 1;
+ rc = pci_enable_msi(efx->pci_dev);
+ if (rc == 0) {
+ efx->channel[0].irq = efx->pci_dev->irq;
+ efx->channel[0].has_interrupt = 1;
+ } else {
+ EFX_ERR(efx, "could not enable MSI\n");
+ efx->interrupt_mode = EFX_INT_MODE_LEGACY;
+ }
+ }
+
+ /* Assume legacy interrupts */
+ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
+ efx->rss_queues = 1;
+ /* Every channel is interruptible */
+ for (i = 0; i < EFX_MAX_CHANNELS; i++)
+ efx->channel[i].has_interrupt = 1;
+ efx->legacy_irq = efx->pci_dev->irq;
+ }
+}
+
+static void efx_remove_interrupts(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ /* Remove MSI/MSI-X interrupts */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ channel->irq = 0;
+ pci_disable_msi(efx->pci_dev);
+ pci_disable_msix(efx->pci_dev);
+
+ /* Remove legacy interrupt */
+ efx->legacy_irq = 0;
+}
+
+/* Select number of used resources
+ * Should be called after probe_interrupts()
+ */
+static void efx_select_used(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int i;
+
+ /* TX queues. One per port per channel with TX capability
+ * (more than one per port won't work on Linux, due to out
+ * of order issues... but will be fine on Solaris)
+ */
+ tx_queue = &efx->tx_queue[0];
+
+ /* Perform this for each channel with TX capabilities.
+ * At the moment, we only support a single TX queue
+ */
+ tx_queue->used = 1;
+ if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
+ tx_queue->channel = &efx->channel[1];
+ else
+ tx_queue->channel = &efx->channel[0];
+ tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+ tx_queue++;
+
+ /* RX queues. Each has a dedicated channel. */
+ for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
+ rx_queue = &efx->rx_queue[i];
+
+ if (i < efx->rss_queues) {
+ rx_queue->used = 1;
+ /* If we allow multiple RX queues per channel
+ * we need to decide that here
+ */
+ rx_queue->channel = &efx->channel[rx_queue->queue];
+ rx_queue->channel->used_flags |= EFX_USED_BY_RX;
+ rx_queue++;
+ }
+ }
+}
+
+static int efx_probe_nic(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "creating NIC\n");
+
+ /* Carry out hardware-type specific initialisation */
+ rc = falcon_probe_nic(efx);
+ if (rc)
+ return rc;
+
+ /* Determine the number of channels and RX queues by trying to hook
+ * in MSI-X interrupts. */
+ efx_probe_interrupts(efx);
+
+ /* Determine number of RX queues and TX queues */
+ efx_select_used(efx);
+
+ /* Initialise the interrupt moderation settings */
+ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
+
+ return 0;
+}
+
+static void efx_remove_nic(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "destroying NIC\n");
+
+ efx_remove_interrupts(efx);
+ falcon_remove_nic(efx);
+}
+
+/**************************************************************************
+ *
+ * NIC startup/shutdown
+ *
+ *************************************************************************/
+
+static int efx_probe_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ /* Create NIC */
+ rc = efx_probe_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to create NIC\n");
+ goto fail1;
+ }
+
+ /* Create port */
+ rc = efx_probe_port(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to create port\n");
+ goto fail2;
+ }
+
+ /* Create channels */
+ efx_for_each_channel(channel, efx) {
+ rc = efx_probe_channel(channel);
+ if (rc) {
+ EFX_ERR(efx, "failed to create channel %d\n",
+ channel->channel);
+ goto fail3;
+ }
+ }
+
+ return 0;
+
+ fail3:
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+ efx_remove_port(efx);
+ fail2:
+ efx_remove_nic(efx);
+ fail1:
+ return rc;
+}
+
+/* Called after previous invocation(s) of efx_stop_all, restarts the
+ * port, kernel transmit queue, NAPI processing and hardware interrupts,
+ * and ensures that the port is scheduled to be reconfigured.
+ * This function is safe to call multiple times when the NIC is in any
+ * state. */
+static void efx_start_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* Check that it is appropriate to restart the interface. All
+ * of these flags are safe to read under just the rtnl lock */
+ if (efx->port_enabled)
+ return;
+ if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT))
+ return;
+ if (NET_DEV_REGISTERED(efx) && !netif_running(efx->net_dev))
+ return;
+
+ /* Mark the port as enabled so port reconfigurations can start, then
+ * restart the transmit interface early so the watchdog timer stops */
+ efx_start_port(efx);
+ efx_wake_queue(efx);
+
+ efx_for_each_channel(channel, efx)
+ efx_start_channel(channel);
+
+ falcon_enable_interrupts(efx);
+
+ /* Start hardware monitor if we're in RUNNING */
+ if (efx->state == STATE_RUNNING)
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+}
+
+/* Flush all delayed work. Should only be called when no more delayed work
+ * will be scheduled. This doesn't flush pending online resets (efx_reset),
+ * since we're holding the rtnl_lock at this point. */
+static void efx_flush_all(struct efx_nic *efx)
+{
+ struct efx_rx_queue *rx_queue;
+
+ /* Make sure the hardware monitor is stopped */
+ cancel_delayed_work_sync(&efx->monitor_work);
+
+ /* Ensure that all RX slow refills are complete. */
+ efx_for_each_rx_queue(rx_queue, efx) {
+ cancel_delayed_work_sync(&rx_queue->work);
+ }
+
+ /* Stop scheduled port reconfigurations */
+ cancel_work_sync(&efx->reconfigure_work);
+
+}
+
+/* Quiesce hardware and software without bringing the link down.
+ * Safe to call multiple times, when the nic and interface is in any
+ * state. The caller is guaranteed to subsequently be in a position
+ * to modify any hardware and software state they see fit without
+ * taking locks. */
+static void efx_stop_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* port_enabled can be read safely under the rtnl lock */
+ if (!efx->port_enabled)
+ return;
+
+ /* Disable interrupts and wait for ISR to complete */
+ falcon_disable_interrupts(efx);
+ if (efx->legacy_irq)
+ synchronize_irq(efx->legacy_irq);
+ efx_for_each_channel_with_interrupt(channel, efx)
+ if (channel->irq)
+ synchronize_irq(channel->irq);
+
+ /* Stop all NAPI processing and synchronous rx refills */
+ efx_for_each_channel(channel, efx)
+ efx_stop_channel(channel);
+
+ /* Stop all asynchronous port reconfigurations. Since all
+ * event processing has already been stopped, there is no
+ * window to loose phy events */
+ efx_stop_port(efx);
+
+ /* Flush reconfigure_work, refill_workqueue, monitor_work */
+ efx_flush_all(efx);
+
+ /* Isolate the MAC from the TX and RX engines, so that queue
+ * flushes will complete in a timely fashion. */
+ falcon_deconfigure_mac_wrapper(efx);
+ falcon_drain_tx_fifo(efx);
+
+ /* Stop the kernel transmit interface late, so the watchdog
+ * timer isn't ticking over the flush */
+ efx_stop_queue(efx);
+ if (NET_DEV_REGISTERED(efx)) {
+ netif_tx_lock_bh(efx->net_dev);
+ netif_tx_unlock_bh(efx->net_dev);
+ }
+}
+
+static void efx_remove_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+ efx_remove_port(efx);
+ efx_remove_nic(efx);
+}
+
+/* A convinience function to safely flush all the queues */
+int efx_flush_queues(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ efx_stop_all(efx);
+
+ efx_fini_channels(efx);
+ rc = efx_init_channels(efx);
+ if (rc) {
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ return rc;
+ }
+
+ efx_start_all(efx);
+
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * Interrupt moderation
+ *
+ **************************************************************************/
+
+/* Set interrupt moderation parameters */
+void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ efx_for_each_tx_queue(tx_queue, efx)
+ tx_queue->channel->irq_moderation = tx_usecs;
+
+ efx_for_each_rx_queue(rx_queue, efx)
+ rx_queue->channel->irq_moderation = rx_usecs;
+}
+
+/**************************************************************************
+ *
+ * Hardware monitor
+ *
+ **************************************************************************/
+
+/* Run periodically off the general workqueue. Serialised against
+ * efx_reconfigure_port via the mac_lock */
+static void efx_monitor(struct work_struct *data)
+{
+ struct efx_nic *efx = container_of(data, struct efx_nic,
+ monitor_work.work);
+ int rc = 0;
+
+ EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
+ raw_smp_processor_id());
+
+
+ /* If the mac_lock is already held then it is likely a port
+ * reconfiguration is already in place, which will likely do
+ * most of the work of check_hw() anyway. */
+ if (!mutex_trylock(&efx->mac_lock)) {
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+ return;
+ }
+
+ if (efx->port_enabled)
+ rc = falcon_check_xmac(efx);
+ mutex_unlock(&efx->mac_lock);
+
+ if (rc) {
+ if (monitor_reset) {
+ EFX_ERR(efx, "hardware monitor detected a fault: "
+ "triggering reset\n");
+ efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+ } else {
+ EFX_ERR(efx, "hardware monitor detected a fault, "
+ "skipping reset\n");
+ }
+ }
+
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+}
+
+/**************************************************************************
+ *
+ * ioctls
+ *
+ *************************************************************************/
+
+/* Net device ioctl
+ * Context: process, rtnl_lock() held.
+ */
+static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
+}
+
+/**************************************************************************
+ *
+ * NAPI interface
+ *
+ **************************************************************************/
+
+static int efx_init_napi(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ efx_for_each_channel(channel, efx) {
+ channel->napi_dev = efx->net_dev;
+ rc = efx_lro_init(&channel->lro_mgr, efx);
+ if (rc)
+ goto err;
+ }
+ return 0;
+ err:
+ efx_fini_napi(efx);
+ return rc;
+}
+
+static void efx_fini_napi(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx) {
+ efx_lro_fini(&channel->lro_mgr);
+ channel->napi_dev = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * Kernel netpoll interface
+ *
+ *************************************************************************/
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/* Although in the common case interrupts will be disabled, this is not
+ * guaranteed. However, all our work happens inside the NAPI callback,
+ * so no locking is required.
+ */
+static void efx_netpoll(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_channel *channel;
+
+ efx_for_each_channel_with_interrupt(channel, efx)
+ efx_schedule_channel(channel);
+}
+
+#endif
+
+/**************************************************************************
+ *
+ * Kernel net device interface
+ *
+ *************************************************************************/
+
+/* Context: process, rtnl_lock() held. */
+static int efx_net_open(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
+ raw_smp_processor_id());
+
+ efx_start_all(efx);
+ return 0;
+}
+
+/* Context: process, rtnl_lock() held.
+ * Note that the kernel will ignore our return code; this method
+ * should really be a void.
+ */
+static int efx_net_stop(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
+ raw_smp_processor_id());
+
+ /* Stop the device and flush all the channels */
+ efx_stop_all(efx);
+ efx_fini_channels(efx);
+ rc = efx_init_channels(efx);
+ if (rc)
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+
+ return 0;
+}
+
+/* Context: process, dev_base_lock held, non-blocking. */
+static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ struct net_device_stats *stats = &net_dev->stats;
+
+ if (!spin_trylock(&efx->stats_lock))
+ return stats;
+ if (efx->state == STATE_RUNNING) {
+ falcon_update_stats_xmac(efx);
+ falcon_update_nic_stats(efx);
+ }
+ spin_unlock(&efx->stats_lock);
+
+ stats->rx_packets = mac_stats->rx_packets;
+ stats->tx_packets = mac_stats->tx_packets;
+ stats->rx_bytes = mac_stats->rx_bytes;
+ stats->tx_bytes = mac_stats->tx_bytes;
+ stats->multicast = mac_stats->rx_multicast;
+ stats->collisions = mac_stats->tx_collision;
+ stats->rx_length_errors = (mac_stats->rx_gtjumbo +
+ mac_stats->rx_length_error);
+ stats->rx_over_errors = efx->n_rx_nodesc_drop_cnt;
+ stats->rx_crc_errors = mac_stats->rx_bad;
+ stats->rx_frame_errors = mac_stats->rx_align_error;
+ stats->rx_fifo_errors = mac_stats->rx_overflow;
+ stats->rx_missed_errors = mac_stats->rx_missed;
+ stats->tx_window_errors = mac_stats->tx_late_collision;
+
+ stats->rx_errors = (stats->rx_length_errors +
+ stats->rx_over_errors +
+ stats->rx_crc_errors +
+ stats->rx_frame_errors +
+ stats->rx_fifo_errors +
+ stats->rx_missed_errors +
+ mac_stats->rx_symbol_error);
+ stats->tx_errors = (stats->tx_window_errors +
+ mac_stats->tx_bad);
+
+ return stats;
+}
+
+/* Context: netif_tx_lock held, BHs disabled. */
+static void efx_watchdog(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
+ atomic_read(&efx->netif_stop_count), efx->port_enabled,
+ monitor_reset ? "resetting channels" : "skipping reset");
+
+ if (monitor_reset)
+ efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+}
+
+
+/* Context: process, rtnl_lock() held. */
+static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc = 0;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ if (new_mtu > EFX_MAX_MTU)
+ return -EINVAL;
+
+ efx_stop_all(efx);
+
+ EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
+
+ efx_fini_channels(efx);
+ net_dev->mtu = new_mtu;
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail;
+
+ efx_start_all(efx);
+ return rc;
+
+ fail:
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ return rc;
+}
+
+static int efx_set_mac_address(struct net_device *net_dev, void *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct sockaddr *addr = data;
+ char *new_addr = addr->sa_data;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ if (!is_valid_ether_addr(new_addr)) {
+ DECLARE_MAC_BUF(mac);
+ EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n",
+ print_mac(mac, new_addr));
+ return -EINVAL;
+ }
+
+ memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
+
+ /* Reconfigure the MAC */
+ efx_reconfigure_port(efx);
+
+ return 0;
+}
+
+/* Context: netif_tx_lock held, BHs disabled. */
+static void efx_set_multicast_list(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct dev_mc_list *mc_list = net_dev->mc_list;
+ union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+ int promiscuous;
+ u32 crc;
+ int bit;
+ int i;
+
+ /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */
+ promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0;
+ if (efx->promiscuous != promiscuous) {
+ efx->promiscuous = promiscuous;
+ /* Close the window between efx_stop_port() and efx_flush_all()
+ * by only queuing work when the port is enabled. */
+ if (efx->port_enabled)
+ queue_work(efx->workqueue, &efx->reconfigure_work);
+ }
+
+ /* Build multicast hash table */
+ if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+ memset(mc_hash, 0xff, sizeof(*mc_hash));
+ } else {
+ memset(mc_hash, 0x00, sizeof(*mc_hash));
+ for (i = 0; i < net_dev->mc_count; i++) {
+ crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr);
+ bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
+ set_bit_le(bit, mc_hash->byte);
+ mc_list = mc_list->next;
+ }
+ }
+
+ /* Create and activate new global multicast hash table */
+ falcon_set_multicast_hash(efx);
+}
+
+static int efx_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *net_dev = (struct net_device *)ptr;
+
+ if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
+ struct efx_nic *efx = net_dev->priv;
+
+ strcpy(efx->name, net_dev->name);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block efx_netdev_notifier = {
+ .notifier_call = efx_netdev_event,
+};
+
+static int efx_register_netdev(struct efx_nic *efx)
+{
+ struct net_device *net_dev = efx->net_dev;
+ int rc;
+
+ net_dev->watchdog_timeo = 5 * HZ;
+ net_dev->irq = efx->pci_dev->irq;
+ net_dev->open = efx_net_open;
+ net_dev->stop = efx_net_stop;
+ net_dev->get_stats = efx_net_stats;
+ net_dev->tx_timeout = &efx_watchdog;
+ net_dev->hard_start_xmit = efx_hard_start_xmit;
+ net_dev->do_ioctl = efx_ioctl;
+ net_dev->change_mtu = efx_change_mtu;
+ net_dev->set_mac_address = efx_set_mac_address;
+ net_dev->set_multicast_list = efx_set_multicast_list;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ net_dev->poll_controller = efx_netpoll;
+#endif
+ SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
+ SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
+
+ /* Always start with carrier off; PHY events will detect the link */
+ netif_carrier_off(efx->net_dev);
+
+ /* Clear MAC statistics */
+ falcon_update_stats_xmac(efx);
+ memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
+
+ rc = register_netdev(net_dev);
+ if (rc) {
+ EFX_ERR(efx, "could not register net dev\n");
+ return rc;
+ }
+ strcpy(efx->name, net_dev->name);
+
+ return 0;
+}
+
+static void efx_unregister_netdev(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+
+ if (!efx->net_dev)
+ return;
+
+ BUG_ON(efx->net_dev->priv != efx);
+
+ /* Free up any skbs still remaining. This has to happen before
+ * we try to unregister the netdev as running their destructors
+ * may be needed to get the device ref. count to 0. */
+ efx_for_each_tx_queue(tx_queue, efx)
+ efx_release_tx_buffers(tx_queue);
+
+ if (NET_DEV_REGISTERED(efx)) {
+ strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
+ unregister_netdev(efx->net_dev);
+ }
+}
+
+/**************************************************************************
+ *
+ * Device reset and suspend
+ *
+ **************************************************************************/
+
+/* The final hardware and software finalisation before reset. */
+static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ int rc;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ rc = falcon_xmac_get_settings(efx, ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not back up PHY settings\n");
+ goto fail;
+ }
+
+ efx_fini_channels(efx);
+ return 0;
+
+ fail:
+ return rc;
+}
+
+/* The first part of software initialisation after a hardware reset
+ * This function does not handle serialisation with the kernel, it
+ * assumes the caller has done this */
+static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ int rc;
+
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail1;
+
+ /* Restore MAC and PHY settings. */
+ rc = falcon_xmac_set_settings(efx, ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not restore PHY settings\n");
+ goto fail2;
+ }
+
+ return 0;
+
+ fail2:
+ efx_fini_channels(efx);
+ fail1:
+ return rc;
+}
+
+/* Reset the NIC as transparently as possible. Do not reset the PHY
+ * Note that the reset may fail, in which case the card will be left
+ * in a most-probably-unusable state.
+ *
+ * This function will sleep. You cannot reset from within an atomic
+ * state; use efx_schedule_reset() instead.
+ *
+ * Grabs the rtnl_lock.
+ */
+static int efx_reset(struct efx_nic *efx)
+{
+ struct ethtool_cmd ecmd;
+ enum reset_type method = efx->reset_pending;
+ int rc;
+
+ /* Serialise with kernel interfaces */
+ rtnl_lock();
+
+ /* If we're not RUNNING then don't reset. Leave the reset_pending
+ * flag set so that efx_pci_probe_main will be retried */
+ if (efx->state != STATE_RUNNING) {
+ EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
+ goto unlock_rtnl;
+ }
+
+ efx->state = STATE_RESETTING;
+ EFX_INFO(efx, "resetting (%d)\n", method);
+
+ /* The net_dev->get_stats handler is quite slow, and will fail
+ * if a fetch is pending over reset. Serialise against it. */
+ spin_lock(&efx->stats_lock);
+ spin_unlock(&efx->stats_lock);
+
+ efx_stop_all(efx);
+ mutex_lock(&efx->mac_lock);
+
+ rc = efx_reset_down(efx, &ecmd);
+ if (rc)
+ goto fail1;
+
+ rc = falcon_reset_hw(efx, method);
+ if (rc) {
+ EFX_ERR(efx, "failed to reset hardware\n");
+ goto fail2;
+ }
+
+ /* Allow resets to be rescheduled. */
+ efx->reset_pending = RESET_TYPE_NONE;
+
+ /* Reinitialise bus-mastering, which may have been turned off before
+ * the reset was scheduled. This is still appropriate, even in the
+ * RESET_TYPE_DISABLE since this driver generally assumes the hardware
+ * can respond to requests. */
+ pci_set_master(efx->pci_dev);
+
+ /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE
+ * case so the driver can talk to external SRAM */
+ rc = falcon_init_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise NIC\n");
+ goto fail3;
+ }
+
+ /* Leave device stopped if necessary */
+ if (method == RESET_TYPE_DISABLE) {
+ /* Reinitialise the device anyway so the driver unload sequence
+ * can talk to the external SRAM */
+ (void) falcon_init_nic(efx);
+ rc = -EIO;
+ goto fail4;
+ }
+
+ rc = efx_reset_up(efx, &ecmd);
+ if (rc)
+ goto fail5;
+
+ mutex_unlock(&efx->mac_lock);
+ EFX_LOG(efx, "reset complete\n");
+
+ efx->state = STATE_RUNNING;
+ efx_start_all(efx);
+
+ unlock_rtnl:
+ rtnl_unlock();
+ return 0;
+
+ fail5:
+ fail4:
+ fail3:
+ fail2:
+ fail1:
+ EFX_ERR(efx, "has been disabled\n");
+ efx->state = STATE_DISABLED;
+
+ mutex_unlock(&efx->mac_lock);
+ rtnl_unlock();
+ efx_unregister_netdev(efx);
+ efx_fini_port(efx);
+ return rc;
+}
+
+/* The worker thread exists so that code that cannot sleep can
+ * schedule a reset for later.
+ */
+static void efx_reset_work(struct work_struct *data)
+{
+ struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
+
+ efx_reset(nic);
+}
+
+void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
+{
+ enum reset_type method;
+
+ if (efx->reset_pending != RESET_TYPE_NONE) {
+ EFX_INFO(efx, "quenching already scheduled reset\n");
+ return;
+ }
+
+ switch (type) {
+ case RESET_TYPE_INVISIBLE:
+ case RESET_TYPE_ALL:
+ case RESET_TYPE_WORLD:
+ case RESET_TYPE_DISABLE:
+ method = type;
+ break;
+ case RESET_TYPE_RX_RECOVERY:
+ case RESET_TYPE_RX_DESC_FETCH:
+ case RESET_TYPE_TX_DESC_FETCH:
+ case RESET_TYPE_TX_SKIP:
+ method = RESET_TYPE_INVISIBLE;
+ break;
+ default:
+ method = RESET_TYPE_ALL;
+ break;
+ }
+
+ if (method != type)
+ EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method);
+ else
+ EFX_LOG(efx, "scheduling reset (%d)\n", method);
+
+ efx->reset_pending = method;
+
+ queue_work(efx->workqueue, &efx->reset_work);
+}
+
+/**************************************************************************
+ *
+ * List of NICs we support
+ *
+ **************************************************************************/
+
+/* PCI device ID table */
+static struct pci_device_id efx_pci_table[] __devinitdata = {
+ {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
+ .driver_data = (unsigned long) &falcon_a_nic_type},
+ {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
+ .driver_data = (unsigned long) &falcon_b_nic_type},
+ {0} /* end of list */
+};
+
+/**************************************************************************
+ *
+ * Dummy PHY/MAC/Board operations
+ *
+ * Can be used where the MAC does not implement this operation
+ * Needed so all function pointers are valid and do not have to be tested
+ * before use
+ *
+ **************************************************************************/
+int efx_port_dummy_op_int(struct efx_nic *efx)
+{
+ return 0;
+}
+void efx_port_dummy_op_void(struct efx_nic *efx) {}
+void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {}
+
+static struct efx_phy_operations efx_dummy_phy_operations = {
+ .init = efx_port_dummy_op_int,
+ .reconfigure = efx_port_dummy_op_void,
+ .check_hw = efx_port_dummy_op_int,
+ .fini = efx_port_dummy_op_void,
+ .clear_interrupt = efx_port_dummy_op_void,
+ .reset_xaui = efx_port_dummy_op_void,
+};
+
+/* Dummy board operations */
+static int efx_nic_dummy_op_int(struct efx_nic *nic)
+{
+ return 0;
+}
+
+static struct efx_board efx_dummy_board_info = {
+ .init = efx_nic_dummy_op_int,
+ .init_leds = efx_port_dummy_op_int,
+ .set_fault_led = efx_port_dummy_op_blink,
+};
+
+/**************************************************************************
+ *
+ * Data housekeeping
+ *
+ **************************************************************************/
+
+/* This zeroes out and then fills in the invariants in a struct
+ * efx_nic (including all sub-structures).
+ */
+static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
+ struct pci_dev *pci_dev, struct net_device *net_dev)
+{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int i, rc;
+
+ /* Initialise common structures */
+ memset(efx, 0, sizeof(*efx));
+ spin_lock_init(&efx->biu_lock);
+ spin_lock_init(&efx->phy_lock);
+ INIT_WORK(&efx->reset_work, efx_reset_work);
+ INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
+ efx->pci_dev = pci_dev;
+ efx->state = STATE_INIT;
+ efx->reset_pending = RESET_TYPE_NONE;
+ strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
+ efx->board_info = efx_dummy_board_info;
+
+ efx->net_dev = net_dev;
+ efx->rx_checksum_enabled = 1;
+ spin_lock_init(&efx->netif_stop_lock);
+ spin_lock_init(&efx->stats_lock);
+ mutex_init(&efx->mac_lock);
+ efx->phy_op = &efx_dummy_phy_operations;
+ efx->mii.dev = net_dev;
+ INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
+ atomic_set(&efx->netif_stop_count, 1);
+
+ for (i = 0; i < EFX_MAX_CHANNELS; i++) {
+ channel = &efx->channel[i];
+ channel->efx = efx;
+ channel->channel = i;
+ channel->evqnum = i;
+ channel->work_pending = 0;
+ }
+ for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+ tx_queue = &efx->tx_queue[i];
+ tx_queue->efx = efx;
+ tx_queue->queue = i;
+ tx_queue->buffer = NULL;
+ tx_queue->channel = &efx->channel[0]; /* for safety */
+ tx_queue->tso_headers_free = NULL;
+ }
+ for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
+ rx_queue = &efx->rx_queue[i];
+ rx_queue->efx = efx;
+ rx_queue->queue = i;
+ rx_queue->channel = &efx->channel[0]; /* for safety */
+ rx_queue->buffer = NULL;
+ spin_lock_init(&rx_queue->add_lock);
+ INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+ }
+
+ efx->type = type;
+
+ /* Sanity-check NIC type */
+ EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask &
+ (efx->type->txd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask &
+ (efx->type->rxd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->evq_size &
+ (efx->type->evq_size - 1));
+ /* As close as we can get to guaranteeing that we don't overflow */
+ EFX_BUG_ON_PARANOID(efx->type->evq_size <
+ (efx->type->txd_ring_mask + 1 +
+ efx->type->rxd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS);
+
+ /* Higher numbered interrupt modes are less capable! */
+ efx->interrupt_mode = max(efx->type->max_interrupt_mode,
+ interrupt_mode);
+
+ efx->workqueue = create_singlethread_workqueue("sfc_work");
+ if (!efx->workqueue) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ return 0;
+
+ fail1:
+ return rc;
+}
+
+static void efx_fini_struct(struct efx_nic *efx)
+{
+ if (efx->workqueue) {
+ destroy_workqueue(efx->workqueue);
+ efx->workqueue = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * PCI interface
+ *
+ **************************************************************************/
+
+/* Main body of final NIC shutdown code
+ * This is called only at module unload (or hotplug removal).
+ */
+static void efx_pci_remove_main(struct efx_nic *efx)
+{
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* Skip everything if we never obtained a valid membase */
+ if (!efx->membase)
+ return;
+
+ efx_fini_channels(efx);
+ efx_fini_port(efx);
+
+ /* Shutdown the board, then the NIC and board state */
+ falcon_fini_interrupt(efx);
+
+ efx_fini_napi(efx);
+ efx_remove_all(efx);
+}
+
+/* Final NIC shutdown
+ * This is called only at module unload (or hotplug removal).
+ */
+static void efx_pci_remove(struct pci_dev *pci_dev)
+{
+ struct efx_nic *efx;
+
+ efx = pci_get_drvdata(pci_dev);
+ if (!efx)
+ return;
+
+ /* Mark the NIC as fini, then stop the interface */
+ rtnl_lock();
+ efx->state = STATE_FINI;
+ dev_close(efx->net_dev);
+
+ /* Allow any queued efx_resets() to complete */
+ rtnl_unlock();
+
+ if (efx->membase == NULL)
+ goto out;
+
+ efx_unregister_netdev(efx);
+
+ /* Wait for any scheduled resets to complete. No more will be
+ * scheduled from this point because efx_stop_all() has been
+ * called, we are no longer registered with driverlink, and
+ * the net_device's have been removed. */
+ flush_workqueue(efx->workqueue);
+
+ efx_pci_remove_main(efx);
+
+out:
+ efx_fini_io(efx);
+ EFX_LOG(efx, "shutdown successful\n");
+
+ pci_set_drvdata(pci_dev, NULL);
+ efx_fini_struct(efx);
+ free_netdev(efx->net_dev);
+};
+
+/* Main body of NIC initialisation
+ * This is called at module load (or hotplug insertion, theoretically).
+ */
+static int efx_pci_probe_main(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Do start-of-day initialisation */
+ rc = efx_probe_all(efx);
+ if (rc)
+ goto fail1;
+
+ rc = efx_init_napi(efx);
+ if (rc)
+ goto fail2;
+
+ /* Initialise the board */
+ rc = efx->board_info.init(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise board\n");
+ goto fail3;
+ }
+
+ rc = falcon_init_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise NIC\n");
+ goto fail4;
+ }
+
+ rc = efx_init_port(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise port\n");
+ goto fail5;
+ }
+
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail6;
+
+ rc = falcon_init_interrupt(efx);
+ if (rc)
+ goto fail7;
+
+ return 0;
+
+ fail7:
+ efx_fini_channels(efx);
+ fail6:
+ efx_fini_port(efx);
+ fail5:
+ fail4:
+ fail3:
+ efx_fini_napi(efx);
+ fail2:
+ efx_remove_all(efx);
+ fail1:
+ return rc;
+}
+
+/* NIC initialisation
+ *
+ * This is called at module load (or hotplug insertion,
+ * theoretically). It sets up PCI mappings, tests and resets the NIC,
+ * sets up and registers the network devices with the kernel and hooks
+ * the interrupt service routine. It does not prepare the device for
+ * transmission; this is left to the first time one of the network
+ * interfaces is brought up (i.e. efx_net_open).
+ */
+static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *entry)
+{
+ struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
+ struct net_device *net_dev;
+ struct efx_nic *efx;
+ int i, rc;
+
+ /* Allocate and initialise a struct net_device and struct efx_nic */
+ net_dev = alloc_etherdev(sizeof(*efx));
+ if (!net_dev)
+ return -ENOMEM;
+ net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_HIGHDMA | NETIF_F_TSO);
+ if (lro)
+ net_dev->features |= NETIF_F_LRO;
+ efx = net_dev->priv;
+ pci_set_drvdata(pci_dev, efx);
+ rc = efx_init_struct(efx, type, pci_dev, net_dev);
+ if (rc)
+ goto fail1;
+
+ EFX_INFO(efx, "Solarflare Communications NIC detected\n");
+
+ /* Set up basic I/O (BAR mappings etc) */
+ rc = efx_init_io(efx);
+ if (rc)
+ goto fail2;
+
+ /* No serialisation is required with the reset path because
+ * we're in STATE_INIT. */
+ for (i = 0; i < 5; i++) {
+ rc = efx_pci_probe_main(efx);
+ if (rc == 0)
+ break;
+
+ /* Serialise against efx_reset(). No more resets will be
+ * scheduled since efx_stop_all() has been called, and we
+ * have not and never have been registered with either
+ * the rtnetlink or driverlink layers. */
+ cancel_work_sync(&efx->reset_work);
+
+ /* Retry if a recoverably reset event has been scheduled */
+ if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
+ (efx->reset_pending != RESET_TYPE_ALL))
+ goto fail3;
+
+ efx->reset_pending = RESET_TYPE_NONE;
+ }
+
+ if (rc) {
+ EFX_ERR(efx, "Could not reset NIC\n");
+ goto fail4;
+ }
+
+ /* Switch to the running state before we expose the device to
+ * the OS. This is to ensure that the initial gathering of
+ * MAC stats succeeds. */
+ rtnl_lock();
+ efx->state = STATE_RUNNING;
+ rtnl_unlock();
+
+ rc = efx_register_netdev(efx);
+ if (rc)
+ goto fail5;
+
+ EFX_LOG(efx, "initialisation successful\n");
+
+ return 0;
+
+ fail5:
+ efx_pci_remove_main(efx);
+ fail4:
+ fail3:
+ efx_fini_io(efx);
+ fail2:
+ efx_fini_struct(efx);
+ fail1:
+ EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+ free_netdev(net_dev);
+ return rc;
+}
+
+static struct pci_driver efx_pci_driver = {
+ .name = EFX_DRIVER_NAME,
+ .id_table = efx_pci_table,
+ .probe = efx_pci_probe,
+ .remove = efx_pci_remove,
+};
+
+/**************************************************************************
+ *
+ * Kernel module interface
+ *
+ *************************************************************************/
+
+module_param(interrupt_mode, uint, 0444);
+MODULE_PARM_DESC(interrupt_mode,
+ "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
+
+static int __init efx_init_module(void)
+{
+ int rc;
+
+ printk(KERN_INFO "Solarflare NET driver v" EFX_DRIVER_VERSION "\n");
+
+ rc = register_netdevice_notifier(&efx_netdev_notifier);
+ if (rc)
+ goto err_notifier;
+
+ refill_workqueue = create_workqueue("sfc_refill");
+ if (!refill_workqueue) {
+ rc = -ENOMEM;
+ goto err_refill;
+ }
+
+ rc = pci_register_driver(&efx_pci_driver);
+ if (rc < 0)
+ goto err_pci;
+
+ return 0;
+
+ err_pci:
+ destroy_workqueue(refill_workqueue);
+ err_refill:
+ unregister_netdevice_notifier(&efx_netdev_notifier);
+ err_notifier:
+ return rc;
+}
+
+static void __exit efx_exit_module(void)
+{
+ printk(KERN_INFO "Solarflare NET driver unloading\n");
+
+ pci_unregister_driver(&efx_pci_driver);
+ destroy_workqueue(refill_workqueue);
+ unregister_netdevice_notifier(&efx_netdev_notifier);
+
+}
+
+module_init(efx_init_module);
+module_exit(efx_exit_module);
+
+MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
+ "Solarflare Communications");
+MODULE_DESCRIPTION("Solarflare Communications network driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, efx_pci_table);
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
new file mode 100644
index 000000000000..3b2f69f4a9ab
--- /dev/null
+++ b/drivers/net/sfc/efx.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_EFX_H
+#define EFX_EFX_H
+
+#include "net_driver.h"
+
+/* PCI IDs */
+#define EFX_VENDID_SFC 0x1924
+#define FALCON_A_P_DEVID 0x0703
+#define FALCON_A_S_DEVID 0x6703
+#define FALCON_B_P_DEVID 0x0710
+
+/* TX */
+extern int efx_xmit(struct efx_nic *efx,
+ struct efx_tx_queue *tx_queue, struct sk_buff *skb);
+extern void efx_stop_queue(struct efx_nic *efx);
+extern void efx_wake_queue(struct efx_nic *efx);
+
+/* RX */
+extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
+extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+ unsigned int len, int checksummed, int discard);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+
+/* Channels */
+extern void efx_process_channel_now(struct efx_channel *channel);
+extern int efx_flush_queues(struct efx_nic *efx);
+
+/* Ports */
+extern void efx_reconfigure_port(struct efx_nic *efx);
+
+/* Global */
+extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
+extern void efx_suspend(struct efx_nic *efx);
+extern void efx_resume(struct efx_nic *efx);
+extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
+ int rx_usecs);
+extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
+extern void efx_hex_dump(const u8 *, unsigned int, const char *);
+
+/* Dummy PHY ops for PHY drivers */
+extern int efx_port_dummy_op_int(struct efx_nic *efx);
+extern void efx_port_dummy_op_void(struct efx_nic *efx);
+extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
+
+
+extern unsigned int efx_monitor_interval;
+
+static inline void efx_schedule_channel(struct efx_channel *channel)
+{
+ EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
+ channel->channel, raw_smp_processor_id());
+ channel->work_pending = 1;
+
+ netif_rx_schedule(channel->napi_dev, &channel->napi_str);
+}
+
+#endif /* EFX_EFX_H */
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
new file mode 100644
index 000000000000..c53290d08e2b
--- /dev/null
+++ b/drivers/net/sfc/enum.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_ENUM_H
+#define EFX_ENUM_H
+
+/**
+ * enum efx_loopback_mode - loopback modes
+ * @LOOPBACK_NONE: no loopback
+ * @LOOPBACK_XGMII: loopback within MAC at XGMII level
+ * @LOOPBACK_XGXS: loopback within MAC at XGXS level
+ * @LOOPBACK_XAUI: loopback within MAC at XAUI level
+ * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level
+ * @LOOPBACK_PCS: loopback within PHY at PCS level
+ * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level
+ * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
+ */
+/* Please keep in order and up-to-date w.r.t the following two #defines */
+enum efx_loopback_mode {
+ LOOPBACK_NONE = 0,
+ LOOPBACK_MAC = 1,
+ LOOPBACK_XGMII = 2,
+ LOOPBACK_XGXS = 3,
+ LOOPBACK_XAUI = 4,
+ LOOPBACK_PHY = 5,
+ LOOPBACK_PHYXS = 6,
+ LOOPBACK_PCS = 7,
+ LOOPBACK_PMAPMD = 8,
+ LOOPBACK_NETWORK = 9,
+ LOOPBACK_MAX
+};
+
+#define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD
+
+extern const char *efx_loopback_mode_names[];
+#define LOOPBACK_MODE_NAME(mode) \
+ STRING_TABLE_LOOKUP(mode, efx_loopback_mode)
+#define LOOPBACK_MODE(efx) \
+ LOOPBACK_MODE_NAME(efx->loopback_mode)
+
+/* These loopbacks occur within the controller */
+#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \
+ (1 << LOOPBACK_XGXS) | \
+ (1 << LOOPBACK_XAUI))
+
+#define LOOPBACK_MASK(_efx) \
+ (1 << (_efx)->loopback_mode)
+
+#define LOOPBACK_INTERNAL(_efx) \
+ ((LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)) ? 1 : 0)
+
+#define LOOPBACK_OUT_OF(_from, _to, _mask) \
+ (((LOOPBACK_MASK(_from) & (_mask)) && \
+ ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0)
+
+/*****************************************************************************/
+
+/**
+ * enum reset_type - reset types
+ *
+ * %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
+ * %RESET_TYPE_DISABLE specify the method/scope of the reset. The
+ * other valuesspecify reasons, which efx_schedule_reset() will choose
+ * a method for.
+ *
+ * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
+ * @RESET_TYPE_ALL: reset everything but PCI core blocks
+ * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
+ * @RESET_TYPE_DISABLE: disable NIC
+ * @RESET_TYPE_MONITOR: reset due to hardware monitor
+ * @RESET_TYPE_INT_ERROR: reset due to internal error
+ * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
+ * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
+ * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
+ * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
+ */
+enum reset_type {
+ RESET_TYPE_NONE = -1,
+ RESET_TYPE_INVISIBLE = 0,
+ RESET_TYPE_ALL = 1,
+ RESET_TYPE_WORLD = 2,
+ RESET_TYPE_DISABLE = 3,
+ RESET_TYPE_MAX_METHOD,
+ RESET_TYPE_MONITOR,
+ RESET_TYPE_INT_ERROR,
+ RESET_TYPE_RX_RECOVERY,
+ RESET_TYPE_RX_DESC_FETCH,
+ RESET_TYPE_TX_DESC_FETCH,
+ RESET_TYPE_TX_SKIP,
+ RESET_TYPE_MAX,
+};
+
+#endif /* EFX_ENUM_H */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
new file mode 100644
index 000000000000..e2c75d101610
--- /dev/null
+++ b/drivers/net/sfc/ethtool.c
@@ -0,0 +1,717 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+#include "net_driver.h"
+#include "selftest.h"
+#include "efx.h"
+#include "ethtool.h"
+#include "falcon.h"
+#include "gmii.h"
+#include "mac.h"
+
+const char *efx_loopback_mode_names[] = {
+ [LOOPBACK_NONE] = "NONE",
+ [LOOPBACK_MAC] = "MAC",
+ [LOOPBACK_XGMII] = "XGMII",
+ [LOOPBACK_XGXS] = "XGXS",
+ [LOOPBACK_XAUI] = "XAUI",
+ [LOOPBACK_PHY] = "PHY",
+ [LOOPBACK_PHYXS] = "PHY(XS)",
+ [LOOPBACK_PCS] = "PHY(PCS)",
+ [LOOPBACK_PMAPMD] = "PHY(PMAPMD)",
+ [LOOPBACK_NETWORK] = "NETWORK",
+};
+
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
+
+struct ethtool_string {
+ char name[ETH_GSTRING_LEN];
+};
+
+struct efx_ethtool_stat {
+ const char *name;
+ enum {
+ EFX_ETHTOOL_STAT_SOURCE_mac_stats,
+ EFX_ETHTOOL_STAT_SOURCE_nic,
+ EFX_ETHTOOL_STAT_SOURCE_channel
+ } source;
+ unsigned offset;
+ u64(*get_stat) (void *field); /* Reader function */
+};
+
+/* Initialiser for a struct #efx_ethtool_stat with type-checking */
+#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
+ get_stat_function) { \
+ .name = #stat_name, \
+ .source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \
+ .offset = ((((field_type *) 0) == \
+ &((struct efx_##source_name *)0)->field) ? \
+ offsetof(struct efx_##source_name, field) : \
+ offsetof(struct efx_##source_name, field)), \
+ .get_stat = get_stat_function, \
+}
+
+static u64 efx_get_uint_stat(void *field)
+{
+ return *(unsigned int *)field;
+}
+
+static u64 efx_get_ulong_stat(void *field)
+{
+ return *(unsigned long *)field;
+}
+
+static u64 efx_get_u64_stat(void *field)
+{
+ return *(u64 *) field;
+}
+
+static u64 efx_get_atomic_stat(void *field)
+{
+ return atomic_read((atomic_t *) field);
+}
+
+#define EFX_ETHTOOL_ULONG_MAC_STAT(field) \
+ EFX_ETHTOOL_STAT(field, mac_stats, field, \
+ unsigned long, efx_get_ulong_stat)
+
+#define EFX_ETHTOOL_U64_MAC_STAT(field) \
+ EFX_ETHTOOL_STAT(field, mac_stats, field, \
+ u64, efx_get_u64_stat)
+
+#define EFX_ETHTOOL_UINT_NIC_STAT(name) \
+ EFX_ETHTOOL_STAT(name, nic, n_##name, \
+ unsigned int, efx_get_uint_stat)
+
+#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \
+ EFX_ETHTOOL_STAT(field, nic, field, \
+ atomic_t, efx_get_atomic_stat)
+
+#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \
+ EFX_ETHTOOL_STAT(field, channel, n_##field, \
+ unsigned int, efx_get_uint_stat)
+
+static struct efx_ethtool_stat efx_ethtool_stats[] = {
+ EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_control),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_good),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_control),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error),
+ EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
+ EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
+};
+
+/* Number of ethtool statistics */
+#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
+
+/**************************************************************************
+ *
+ * Ethtool operations
+ *
+ **************************************************************************
+ */
+
+/* Identify device by flashing LEDs */
+static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ efx->board_info.blink(efx, 1);
+ schedule_timeout_interruptible(seconds * HZ);
+ efx->board_info.blink(efx, 0);
+ return 0;
+}
+
+/* This must be called with rtnl_lock held. */
+int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_get_settings(efx, ecmd);
+ mutex_unlock(&efx->mac_lock);
+
+ return rc;
+}
+
+/* This must be called with rtnl_lock held. */
+int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_set_settings(efx, ecmd);
+ mutex_unlock(&efx->mac_lock);
+ if (!rc)
+ efx_reconfigure_port(efx);
+
+ return rc;
+}
+
+static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *info)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
+}
+
+/**
+ * efx_fill_test - fill in an individual self-test entry
+ * @test_index: Index of the test
+ * @strings: Ethtool strings, or %NULL
+ * @data: Ethtool test results, or %NULL
+ * @test: Pointer to test result (used only if data != %NULL)
+ * @unit_format: Unit name format (e.g. "channel\%d")
+ * @unit_id: Unit id (e.g. 0 for "channel0")
+ * @test_format: Test name format (e.g. "loopback.\%s.tx.sent")
+ * @test_id: Test id (e.g. "PHY" for "loopback.PHY.tx_sent")
+ *
+ * Fill in an individual self-test entry.
+ */
+static void efx_fill_test(unsigned int test_index,
+ struct ethtool_string *strings, u64 *data,
+ int *test, const char *unit_format, int unit_id,
+ const char *test_format, const char *test_id)
+{
+ struct ethtool_string unit_str, test_str;
+
+ /* Fill data value, if applicable */
+ if (data)
+ data[test_index] = *test;
+
+ /* Fill string, if applicable */
+ if (strings) {
+ snprintf(unit_str.name, sizeof(unit_str.name),
+ unit_format, unit_id);
+ snprintf(test_str.name, sizeof(test_str.name),
+ test_format, test_id);
+ snprintf(strings[test_index].name,
+ sizeof(strings[test_index].name),
+ "%-9s%-17s", unit_str.name, test_str.name);
+ }
+}
+
+#define EFX_PORT_NAME "port%d", 0
+#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel
+#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
+#define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
+#define EFX_LOOPBACK_NAME(_mode, _counter) \
+ "loopback.%s." _counter, LOOPBACK_MODE_NAME(mode)
+
+/**
+ * efx_fill_loopback_test - fill in a block of loopback self-test entries
+ * @efx: Efx NIC
+ * @lb_tests: Efx loopback self-test results structure
+ * @mode: Loopback test mode
+ * @test_index: Starting index of the test
+ * @strings: Ethtool strings, or %NULL
+ * @data: Ethtool test results, or %NULL
+ */
+static int efx_fill_loopback_test(struct efx_nic *efx,
+ struct efx_loopback_self_tests *lb_tests,
+ enum efx_loopback_mode mode,
+ unsigned int test_index,
+ struct ethtool_string *strings, u64 *data)
+{
+ struct efx_tx_queue *tx_queue;
+
+ efx_for_each_tx_queue(tx_queue, efx) {
+ efx_fill_test(test_index++, strings, data,
+ &lb_tests->tx_sent[tx_queue->queue],
+ EFX_TX_QUEUE_NAME(tx_queue),
+ EFX_LOOPBACK_NAME(mode, "tx_sent"));
+ efx_fill_test(test_index++, strings, data,
+ &lb_tests->tx_done[tx_queue->queue],
+ EFX_TX_QUEUE_NAME(tx_queue),
+ EFX_LOOPBACK_NAME(mode, "tx_done"));
+ }
+ efx_fill_test(test_index++, strings, data,
+ &lb_tests->rx_good,
+ EFX_PORT_NAME,
+ EFX_LOOPBACK_NAME(mode, "rx_good"));
+ efx_fill_test(test_index++, strings, data,
+ &lb_tests->rx_bad,
+ EFX_PORT_NAME,
+ EFX_LOOPBACK_NAME(mode, "rx_bad"));
+
+ return test_index;
+}
+
+/**
+ * efx_ethtool_fill_self_tests - get self-test details
+ * @efx: Efx NIC
+ * @tests: Efx self-test results structure, or %NULL
+ * @strings: Ethtool strings, or %NULL
+ * @data: Ethtool test results, or %NULL
+ */
+static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
+ struct efx_self_tests *tests,
+ struct ethtool_string *strings,
+ u64 *data)
+{
+ struct efx_channel *channel;
+ unsigned int n = 0;
+ enum efx_loopback_mode mode;
+
+ /* Interrupt */
+ efx_fill_test(n++, strings, data, &tests->interrupt,
+ "core", 0, "interrupt", NULL);
+
+ /* Event queues */
+ efx_for_each_channel(channel, efx) {
+ efx_fill_test(n++, strings, data,
+ &tests->eventq_dma[channel->channel],
+ EFX_CHANNEL_NAME(channel),
+ "eventq.dma", NULL);
+ efx_fill_test(n++, strings, data,
+ &tests->eventq_int[channel->channel],
+ EFX_CHANNEL_NAME(channel),
+ "eventq.int", NULL);
+ efx_fill_test(n++, strings, data,
+ &tests->eventq_poll[channel->channel],
+ EFX_CHANNEL_NAME(channel),
+ "eventq.poll", NULL);
+ }
+
+ /* PHY presence */
+ efx_fill_test(n++, strings, data, &tests->phy_ok,
+ EFX_PORT_NAME, "phy_ok", NULL);
+
+ /* Loopback tests */
+ efx_fill_test(n++, strings, data, &tests->loopback_speed,
+ EFX_PORT_NAME, "loopback.speed", NULL);
+ efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
+ EFX_PORT_NAME, "loopback.full_duplex", NULL);
+ for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+ if (!(efx->loopback_modes & (1 << mode)))
+ continue;
+ n = efx_fill_loopback_test(efx,
+ &tests->loopback[mode], mode, n,
+ strings, data);
+ }
+
+ return n;
+}
+
+static int efx_ethtool_get_stats_count(struct net_device *net_dev)
+{
+ return EFX_ETHTOOL_NUM_STATS;
+}
+
+static int efx_ethtool_self_test_count(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
+}
+
+static void efx_ethtool_get_strings(struct net_device *net_dev,
+ u32 string_set, u8 *strings)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct ethtool_string *ethtool_strings =
+ (struct ethtool_string *)strings;
+ int i;
+
+ switch (string_set) {
+ case ETH_SS_STATS:
+ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
+ strncpy(ethtool_strings[i].name,
+ efx_ethtool_stats[i].name,
+ sizeof(ethtool_strings[i].name));
+ break;
+ case ETH_SS_TEST:
+ efx_ethtool_fill_self_tests(efx, NULL,
+ ethtool_strings, NULL);
+ break;
+ default:
+ /* No other string sets */
+ break;
+ }
+}
+
+static void efx_ethtool_get_stats(struct net_device *net_dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ struct efx_ethtool_stat *stat;
+ struct efx_channel *channel;
+ int i;
+
+ EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
+
+ /* Update MAC and NIC statistics */
+ net_dev->get_stats(net_dev);
+
+ /* Fill detailed statistics buffer */
+ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
+ stat = &efx_ethtool_stats[i];
+ switch (stat->source) {
+ case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
+ data[i] = stat->get_stat((void *)mac_stats +
+ stat->offset);
+ break;
+ case EFX_ETHTOOL_STAT_SOURCE_nic:
+ data[i] = stat->get_stat((void *)efx + stat->offset);
+ break;
+ case EFX_ETHTOOL_STAT_SOURCE_channel:
+ data[i] = 0;
+ efx_for_each_channel(channel, efx)
+ data[i] += stat->get_stat((void *)channel +
+ stat->offset);
+ break;
+ }
+ }
+}
+
+static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
+{
+ int rc;
+
+ /* Our TSO requires TX checksumming, so force TX checksumming
+ * on when TSO is enabled.
+ */
+ if (enable) {
+ rc = efx_ethtool_set_tx_csum(net_dev, 1);
+ if (rc)
+ return rc;
+ }
+
+ return ethtool_op_set_tso(net_dev, enable);
+}
+
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ rc = ethtool_op_set_tx_csum(net_dev, enable);
+ if (rc)
+ return rc;
+
+ efx_flush_queues(efx);
+
+ /* Our TSO requires TX checksumming, so disable TSO when
+ * checksumming is disabled
+ */
+ if (!enable) {
+ rc = efx_ethtool_set_tso(net_dev, 0);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ /* No way to stop the hardware doing the checks; we just
+ * ignore the result.
+ */
+ efx->rx_checksum_enabled = (enable ? 1 : 0);
+
+ return 0;
+}
+
+static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx->rx_checksum_enabled;
+}
+
+static void efx_ethtool_self_test(struct net_device *net_dev,
+ struct ethtool_test *test, u64 *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_self_tests efx_tests;
+ int offline, already_up;
+ int rc;
+
+ ASSERT_RTNL();
+ if (efx->state != STATE_RUNNING) {
+ rc = -EIO;
+ goto fail1;
+ }
+
+ /* We need rx buffers and interrupts. */
+ already_up = (efx->net_dev->flags & IFF_UP);
+ if (!already_up) {
+ rc = dev_open(efx->net_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed opening device.\n");
+ goto fail2;
+ }
+ }
+
+ memset(&efx_tests, 0, sizeof(efx_tests));
+ offline = (test->flags & ETH_TEST_FL_OFFLINE);
+
+ /* Perform online self tests first */
+ rc = efx_online_test(efx, &efx_tests);
+ if (rc)
+ goto out;
+
+ /* Perform offline tests only if online tests passed */
+ if (offline) {
+ /* Stop the kernel from sending packets during the test. */
+ efx_stop_queue(efx);
+ rc = efx_flush_queues(efx);
+ if (!rc)
+ rc = efx_offline_test(efx, &efx_tests,
+ efx->loopback_modes);
+ efx_wake_queue(efx);
+ }
+
+ out:
+ if (!already_up)
+ dev_close(efx->net_dev);
+
+ EFX_LOG(efx, "%s all %sline self-tests\n",
+ rc == 0 ? "passed" : "failed", offline ? "off" : "on");
+
+ fail2:
+ fail1:
+ /* Fill ethtool results structures */
+ efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data);
+ if (rc)
+ test->flags |= ETH_TEST_FL_FAILED;
+}
+
+/* Restart autonegotiation */
+static int efx_ethtool_nway_reset(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return mii_nway_restart(&efx->mii);
+}
+
+static u32 efx_ethtool_get_link(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx->link_up;
+}
+
+static int efx_ethtool_get_coalesce(struct net_device *net_dev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+
+ memset(coalesce, 0, sizeof(*coalesce));
+
+ /* Find lowest IRQ moderation across all used TX queues */
+ coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
+ efx_for_each_tx_queue(tx_queue, efx) {
+ channel = tx_queue->channel;
+ if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
+ if (channel->used_flags != EFX_USED_BY_RX_TX)
+ coalesce->tx_coalesce_usecs_irq =
+ channel->irq_moderation;
+ else
+ coalesce->tx_coalesce_usecs_irq = 0;
+ }
+ }
+
+ /* Find lowest IRQ moderation across all used RX queues */
+ coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
+ efx_for_each_rx_queue(rx_queue, efx) {
+ channel = rx_queue->channel;
+ if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
+ coalesce->rx_coalesce_usecs_irq =
+ channel->irq_moderation;
+ }
+
+ return 0;
+}
+
+/* Set coalescing parameters
+ * The difficulties occur for shared channels
+ */
+static int efx_ethtool_set_coalesce(struct net_device *net_dev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ unsigned tx_usecs, rx_usecs;
+
+ if (coalesce->use_adaptive_rx_coalesce ||
+ coalesce->use_adaptive_tx_coalesce)
+ return -EOPNOTSUPP;
+
+ if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
+ EFX_ERR(efx, "invalid coalescing setting. "
+ "Only rx/tx_coalesce_usecs_irq are supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ rx_usecs = coalesce->rx_coalesce_usecs_irq;
+ tx_usecs = coalesce->tx_coalesce_usecs_irq;
+
+ /* If the channel is shared only allow RX parameters to be set */
+ efx_for_each_tx_queue(tx_queue, efx) {
+ if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
+ tx_usecs) {
+ EFX_ERR(efx, "Channel is shared. "
+ "Only RX coalescing may be set\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
+
+ /* Reset channel to pick up new moderation value. Note that
+ * this may change the value of the irq_moderation field
+ * (e.g. to allow for hardware timer granularity).
+ */
+ efx_for_each_channel(channel, efx)
+ falcon_set_int_moderation(channel);
+
+ return 0;
+}
+
+static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct efx_nic *efx = net_dev->priv;
+ enum efx_fc_type flow_control = efx->flow_control;
+ int rc;
+
+ flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
+ flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
+ flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
+ flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
+
+ /* Try to push the pause parameters */
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_set_pause(efx, flow_control);
+ mutex_unlock(&efx->mac_lock);
+
+ if (!rc)
+ efx_reconfigure_port(efx);
+
+ return rc;
+}
+
+static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+ pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+ pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
+}
+
+
+struct ethtool_ops efx_ethtool_ops = {
+ .get_settings = efx_ethtool_get_settings,
+ .set_settings = efx_ethtool_set_settings,
+ .get_drvinfo = efx_ethtool_get_drvinfo,
+ .nway_reset = efx_ethtool_nway_reset,
+ .get_link = efx_ethtool_get_link,
+ .get_coalesce = efx_ethtool_get_coalesce,
+ .set_coalesce = efx_ethtool_set_coalesce,
+ .get_pauseparam = efx_ethtool_get_pauseparam,
+ .set_pauseparam = efx_ethtool_set_pauseparam,
+ .get_rx_csum = efx_ethtool_get_rx_csum,
+ .set_rx_csum = efx_ethtool_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = efx_ethtool_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = efx_ethtool_set_tso,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
+ .self_test_count = efx_ethtool_self_test_count,
+ .self_test = efx_ethtool_self_test,
+ .get_strings = efx_ethtool_get_strings,
+ .phys_id = efx_ethtool_phys_id,
+ .get_stats_count = efx_ethtool_get_stats_count,
+ .get_ethtool_stats = efx_ethtool_get_stats,
+};
diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h
new file mode 100644
index 000000000000..3628e43df14d
--- /dev/null
+++ b/drivers/net/sfc/ethtool.h
@@ -0,0 +1,27 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_ETHTOOL_H
+#define EFX_ETHTOOL_H
+
+#include "net_driver.h"
+
+/*
+ * Ethtool support
+ */
+
+extern int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd);
+extern int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd);
+
+extern struct ethtool_ops efx_ethtool_ops;
+
+#endif /* EFX_ETHTOOL_H */
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
new file mode 100644
index 000000000000..b57cc68058c0
--- /dev/null
+++ b/drivers/net/sfc/falcon.c
@@ -0,0 +1,2724 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include "net_driver.h"
+#include "bitfield.h"
+#include "efx.h"
+#include "mac.h"
+#include "gmii.h"
+#include "spi.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "boards.h"
+#include "workarounds.h"
+
+/* Falcon hardware control.
+ * Falcon is the internal codename for the SFC4000 controller that is
+ * present in SFE400X evaluation boards
+ */
+
+/**
+ * struct falcon_nic_data - Falcon NIC state
+ * @next_buffer_table: First available buffer table id
+ * @pci_dev2: The secondary PCI device if present
+ */
+struct falcon_nic_data {
+ unsigned next_buffer_table;
+ struct pci_dev *pci_dev2;
+};
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ **************************************************************************
+ */
+
+static int disable_dma_stats;
+
+/* This is set to 16 for a good reason. In summary, if larger than
+ * 16, the descriptor cache holds more than a default socket
+ * buffer's worth of packets (for UDP we can only have at most one
+ * socket buffer's worth outstanding). This combined with the fact
+ * that we only get 1 TX event per descriptor cache means the NIC
+ * goes idle.
+ */
+#define TX_DC_ENTRIES 16
+#define TX_DC_ENTRIES_ORDER 0
+#define TX_DC_BASE 0x130000
+
+#define RX_DC_ENTRIES 64
+#define RX_DC_ENTRIES_ORDER 2
+#define RX_DC_BASE 0x100000
+
+/* RX FIFO XOFF watermark
+ *
+ * When the amount of the RX FIFO increases used increases past this
+ * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
+ * This also has an effect on RX/TX arbitration
+ */
+static int rx_xoff_thresh_bytes = -1;
+module_param(rx_xoff_thresh_bytes, int, 0644);
+MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
+
+/* RX FIFO XON watermark
+ *
+ * When the amount of the RX FIFO used decreases below this
+ * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
+ * This also has an effect on RX/TX arbitration
+ */
+static int rx_xon_thresh_bytes = -1;
+module_param(rx_xon_thresh_bytes, int, 0644);
+MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
+
+/* TX descriptor ring size - min 512 max 4k */
+#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K
+#define FALCON_TXD_RING_SIZE 1024
+#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1)
+
+/* RX descriptor ring size - min 512 max 4k */
+#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K
+#define FALCON_RXD_RING_SIZE 1024
+#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1)
+
+/* Event queue size - max 32k */
+#define FALCON_EVQ_ORDER EVQ_SIZE_4K
+#define FALCON_EVQ_SIZE 4096
+#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
+
+/* Max number of internal errors. After this resets will not be performed */
+#define FALCON_MAX_INT_ERRORS 4
+
+/* Maximum period that we wait for flush events. If the flush event
+ * doesn't arrive in this period of time then we check if the queue
+ * was disabled anyway. */
+#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */
+
+/**************************************************************************
+ *
+ * Falcon constants
+ *
+ **************************************************************************
+ */
+
+/* DMA address mask (up to 46-bit, avoiding compiler warnings)
+ *
+ * Note that it is possible to have a platform with 64-bit longs and
+ * 32-bit DMA addresses, or vice versa. EFX_DMA_MASK takes care of the
+ * platform DMA mask.
+ */
+#if BITS_PER_LONG == 64
+#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL)
+#else
+#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL)
+#endif
+
+/* TX DMA length mask (13-bit) */
+#define FALCON_TX_DMA_MASK (4096 - 1)
+
+/* Size and alignment of special buffers (4KB) */
+#define FALCON_BUF_SIZE 4096
+
+/* Dummy SRAM size code */
+#define SRM_NB_BSZ_ONCHIP_ONLY (-1)
+
+/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
+#define PCI_EXP_DEVCAP_PWR_VAL_LBN 18
+#define PCI_EXP_DEVCAP_PWR_SCL_LBN 26
+#define PCI_EXP_DEVCTL_PAYLOAD_LBN 5
+#define PCI_EXP_LNKSTA_LNK_WID 0x3f0
+#define PCI_EXP_LNKSTA_LNK_WID_LBN 4
+
+#define FALCON_IS_DUAL_FUNC(efx) \
+ (FALCON_REV(efx) < FALCON_REV_B0)
+
+/**************************************************************************
+ *
+ * Falcon hardware access
+ *
+ **************************************************************************/
+
+/* Read the current event from the event queue */
+static inline efx_qword_t *falcon_event(struct efx_channel *channel,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (channel->eventq.addr)) + index);
+}
+
+/* See if an event is present
+ *
+ * We check both the high and low dword of the event for all ones. We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords. This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int falcon_event_present(efx_qword_t *event)
+{
+ return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
+ EFX_DWORD_IS_ALL_ONES(event->dword[1])));
+}
+
+/**************************************************************************
+ *
+ * I2C bus - this is a bit-bashing interface using GPIO pins
+ * Note that it uses the output enables to tristate the outputs
+ * SDA is the data pin and SCL is the clock
+ *
+ **************************************************************************
+ */
+static void falcon_setsdascl(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
+ EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
+ falcon_write(i2c->efx, &reg, GPIO_CTL_REG_KER);
+}
+
+static int falcon_getsda(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+ return EFX_OWORD_FIELD(reg, GPIO3_IN);
+}
+
+static int falcon_getscl(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+ return EFX_DWORD_FIELD(reg, GPIO0_IN);
+}
+
+static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
+ .setsda = falcon_setsdascl,
+ .setscl = falcon_setsdascl,
+ .getsda = falcon_getsda,
+ .getscl = falcon_getscl,
+ .udelay = 100,
+ .mdelay = 10,
+};
+
+/**************************************************************************
+ *
+ * Falcon special buffer handling
+ * Special buffers are used for event queues and the TX and RX
+ * descriptor rings.
+ *
+ *************************************************************************/
+
+/*
+ * Initialise a Falcon special buffer
+ *
+ * This will define a buffer (previously allocated via
+ * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
+ * it to be used for event queues, descriptor rings etc.
+ */
+static int
+falcon_init_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ efx_qword_t buf_desc;
+ int index;
+ dma_addr_t dma_addr;
+ int i;
+
+ EFX_BUG_ON_PARANOID(!buffer->addr);
+
+ /* Write buffer descriptors to NIC */
+ for (i = 0; i < buffer->entries; i++) {
+ index = buffer->index + i;
+ dma_addr = buffer->dma_addr + (i * 4096);
+ EFX_LOG(efx, "mapping special buffer %d at %llx\n",
+ index, (unsigned long long)dma_addr);
+ EFX_POPULATE_QWORD_4(buf_desc,
+ IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K,
+ BUF_ADR_REGION, 0,
+ BUF_ADR_FBUF, (dma_addr >> 12),
+ BUF_OWNER_ID_FBUF, 0);
+ falcon_write_sram(efx, &buf_desc, index);
+ }
+
+ return 0;
+}
+
+/* Unmaps a buffer from Falcon and clears the buffer table entries */
+static void
+falcon_fini_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ efx_oword_t buf_tbl_upd;
+ unsigned int start = buffer->index;
+ unsigned int end = (buffer->index + buffer->entries - 1);
+
+ if (!buffer->entries)
+ return;
+
+ EFX_LOG(efx, "unmapping special buffers %d-%d\n",
+ buffer->index, buffer->index + buffer->entries - 1);
+
+ EFX_POPULATE_OWORD_4(buf_tbl_upd,
+ BUF_UPD_CMD, 0,
+ BUF_CLR_CMD, 1,
+ BUF_CLR_END_ID, end,
+ BUF_CLR_START_ID, start);
+ falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER);
+}
+
+/*
+ * Allocate a new Falcon special buffer
+ *
+ * This allocates memory for a new buffer, clears it and allocates a
+ * new buffer ID range. It does not write into Falcon's buffer table.
+ *
+ * This call will allocate 4KB buffers, since Falcon can't use 8KB
+ * buffers for event queues and descriptor rings.
+ */
+static int falcon_alloc_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer,
+ unsigned int len)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ len = ALIGN(len, FALCON_BUF_SIZE);
+
+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+ &buffer->dma_addr);
+ if (!buffer->addr)
+ return -ENOMEM;
+ buffer->len = len;
+ buffer->entries = len / FALCON_BUF_SIZE;
+ BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1));
+
+ /* All zeros is a potentially valid event so memset to 0xff */
+ memset(buffer->addr, 0xff, len);
+
+ /* Select new buffer ID */
+ buffer->index = nic_data->next_buffer_table;
+ nic_data->next_buffer_table += buffer->entries;
+
+ EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %lx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (unsigned long long)buffer->dma_addr, len,
+ buffer->addr, virt_to_phys(buffer->addr));
+
+ return 0;
+}
+
+static void falcon_free_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ if (!buffer->addr)
+ return;
+
+ EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %lx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (unsigned long long)buffer->dma_addr, buffer->len,
+ buffer->addr, virt_to_phys(buffer->addr));
+
+ pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
+ buffer->dma_addr);
+ buffer->addr = NULL;
+ buffer->entries = 0;
+}
+
+/**************************************************************************
+ *
+ * Falcon generic buffer handling
+ * These buffers are used for interrupt status and MAC stats
+ *
+ **************************************************************************/
+
+static int falcon_alloc_buffer(struct efx_nic *efx,
+ struct efx_buffer *buffer, unsigned int len)
+{
+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+ &buffer->dma_addr);
+ if (!buffer->addr)
+ return -ENOMEM;
+ buffer->len = len;
+ memset(buffer->addr, 0, len);
+ return 0;
+}
+
+static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
+{
+ if (buffer->addr) {
+ pci_free_consistent(efx->pci_dev, buffer->len,
+ buffer->addr, buffer->dma_addr);
+ buffer->addr = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * Falcon TX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified transmit descriptor in the TX
+ * descriptor queue belonging to the specified channel.
+ */
+static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
+}
+
+/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */
+static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
+{
+ unsigned write_ptr;
+ efx_dword_t reg;
+
+ write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
+ EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr);
+ falcon_writel_page(tx_queue->efx, &reg,
+ TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue);
+}
+
+
+/* For each entry inserted into the software descriptor ring, create a
+ * descriptor in the hardware TX descriptor ring (in host memory), and
+ * write a doorbell.
+ */
+void falcon_push_buffers(struct efx_tx_queue *tx_queue)
+{
+
+ struct efx_tx_buffer *buffer;
+ efx_qword_t *txd;
+ unsigned write_ptr;
+
+ BUG_ON(tx_queue->write_count == tx_queue->insert_count);
+
+ do {
+ write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
+ buffer = &tx_queue->buffer[write_ptr];
+ txd = falcon_tx_desc(tx_queue, write_ptr);
+ ++tx_queue->write_count;
+
+ /* Create TX descriptor ring entry */
+ EFX_POPULATE_QWORD_5(*txd,
+ TX_KER_PORT, 0,
+ TX_KER_CONT, buffer->continuation,
+ TX_KER_BYTE_CNT, buffer->len,
+ TX_KER_BUF_REGION, 0,
+ TX_KER_BUF_ADR, buffer->dma_addr);
+ } while (tx_queue->write_count != tx_queue->insert_count);
+
+ wmb(); /* Ensure descriptors are written before they are fetched */
+ falcon_notify_tx_desc(tx_queue);
+}
+
+/* Allocate hardware resources for a TX queue */
+int falcon_probe_tx(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ return falcon_alloc_special_buffer(efx, &tx_queue->txd,
+ FALCON_TXD_RING_SIZE *
+ sizeof(efx_qword_t));
+}
+
+int falcon_init_tx(struct efx_tx_queue *tx_queue)
+{
+ efx_oword_t tx_desc_ptr;
+ struct efx_nic *efx = tx_queue->efx;
+ int rc;
+
+ /* Pin TX descriptor ring */
+ rc = falcon_init_special_buffer(efx, &tx_queue->txd);
+ if (rc)
+ return rc;
+
+ /* Push TX descriptor ring to card */
+ EFX_POPULATE_OWORD_10(tx_desc_ptr,
+ TX_DESCQ_EN, 1,
+ TX_ISCSI_DDIG_EN, 0,
+ TX_ISCSI_HDIG_EN, 0,
+ TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
+ TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum,
+ TX_DESCQ_OWNER_ID, 0,
+ TX_DESCQ_LABEL, tx_queue->queue,
+ TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
+ TX_DESCQ_TYPE, 0,
+ TX_NON_IP_DROP_DIS_B0, 1);
+
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
+ }
+
+ falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+
+ if (FALCON_REV(efx) < FALCON_REV_B0) {
+ efx_oword_t reg;
+
+ BUG_ON(tx_queue->queue >= 128); /* HW limit */
+
+ falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
+ if (efx->net_dev->features & NETIF_F_IP_CSUM)
+ clear_bit_le(tx_queue->queue, (void *)&reg);
+ else
+ set_bit_le(tx_queue->queue, (void *)&reg);
+ falcon_write(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
+ }
+
+ return 0;
+}
+
+static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct efx_channel *channel = &efx->channel[0];
+ efx_oword_t tx_flush_descq;
+ unsigned int read_ptr, i;
+
+ /* Post a flush command */
+ EFX_POPULATE_OWORD_2(tx_flush_descq,
+ TX_FLUSH_DESCQ_CMD, 1,
+ TX_FLUSH_DESCQ, tx_queue->queue);
+ falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
+ msleep(FALCON_FLUSH_TIMEOUT);
+
+ if (EFX_WORKAROUND_7803(efx))
+ return 0;
+
+ /* Look for a flush completed event */
+ read_ptr = channel->eventq_read_ptr;
+ for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+ efx_qword_t *event = falcon_event(channel, read_ptr);
+ int ev_code, ev_sub_code, ev_queue;
+ if (!falcon_event_present(event))
+ break;
+
+ ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID);
+ if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) &&
+ (ev_queue == tx_queue->queue)) {
+ EFX_LOG(efx, "tx queue %d flush command succesful\n",
+ tx_queue->queue);
+ return 0;
+ }
+
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ }
+
+ if (EFX_WORKAROUND_11557(efx)) {
+ efx_oword_t reg;
+ int enabled;
+
+ falcon_read_table(efx, &reg, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+ enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN);
+ if (!enabled) {
+ EFX_LOG(efx, "tx queue %d disabled without a "
+ "flush event seen\n", tx_queue->queue);
+ return 0;
+ }
+ }
+
+ EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
+ return -ETIMEDOUT;
+}
+
+void falcon_fini_tx(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ efx_oword_t tx_desc_ptr;
+
+ /* Stop the hardware using the queue */
+ if (falcon_flush_tx_queue(tx_queue))
+ EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue);
+
+ /* Remove TX descriptor ring from card */
+ EFX_ZERO_OWORD(tx_desc_ptr);
+ falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+
+ /* Unpin TX descriptor ring */
+ falcon_fini_special_buffer(efx, &tx_queue->txd);
+}
+
+/* Free buffers backing TX queue */
+void falcon_remove_tx(struct efx_tx_queue *tx_queue)
+{
+ falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd);
+}
+
+/**************************************************************************
+ *
+ * Falcon RX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified descriptor in the RX descriptor queue */
+static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
+}
+
+/* This creates an entry in the RX descriptor queue */
+static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
+ unsigned index)
+{
+ struct efx_rx_buffer *rx_buf;
+ efx_qword_t *rxd;
+
+ rxd = falcon_rx_desc(rx_queue, index);
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ EFX_POPULATE_QWORD_3(*rxd,
+ RX_KER_BUF_SIZE,
+ rx_buf->len -
+ rx_queue->efx->type->rx_buffer_padding,
+ RX_KER_BUF_REGION, 0,
+ RX_KER_BUF_ADR, rx_buf->dma_addr);
+}
+
+/* This writes to the RX_DESC_WPTR register for the specified receive
+ * descriptor ring.
+ */
+void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
+{
+ efx_dword_t reg;
+ unsigned write_ptr;
+
+ while (rx_queue->notified_count != rx_queue->added_count) {
+ falcon_build_rx_desc(rx_queue,
+ rx_queue->notified_count &
+ FALCON_RXD_RING_MASK);
+ ++rx_queue->notified_count;
+ }
+
+ wmb();
+ write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK;
+ EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr);
+ falcon_writel_page(rx_queue->efx, &reg,
+ RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue);
+}
+
+int falcon_probe_rx(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ return falcon_alloc_special_buffer(efx, &rx_queue->rxd,
+ FALCON_RXD_RING_SIZE *
+ sizeof(efx_qword_t));
+}
+
+int falcon_init_rx(struct efx_rx_queue *rx_queue)
+{
+ efx_oword_t rx_desc_ptr;
+ struct efx_nic *efx = rx_queue->efx;
+ int rc;
+ int is_b0 = FALCON_REV(efx) >= FALCON_REV_B0;
+ int iscsi_digest_en = is_b0;
+
+ EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
+ rx_queue->queue, rx_queue->rxd.index,
+ rx_queue->rxd.index + rx_queue->rxd.entries - 1);
+
+ /* Pin RX descriptor ring */
+ rc = falcon_init_special_buffer(efx, &rx_queue->rxd);
+ if (rc)
+ return rc;
+
+ /* Push RX descriptor ring to card */
+ EFX_POPULATE_OWORD_10(rx_desc_ptr,
+ RX_ISCSI_DDIG_EN, iscsi_digest_en,
+ RX_ISCSI_HDIG_EN, iscsi_digest_en,
+ RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
+ RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum,
+ RX_DESCQ_OWNER_ID, 0,
+ RX_DESCQ_LABEL, rx_queue->queue,
+ RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
+ RX_DESCQ_TYPE, 0 /* kernel queue */ ,
+ /* For >=B0 this is scatter so disable */
+ RX_DESCQ_JUMBO, !is_b0,
+ RX_DESCQ_EN, 1);
+ falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+ return 0;
+}
+
+static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct efx_channel *channel = &efx->channel[0];
+ unsigned int read_ptr, i;
+ efx_oword_t rx_flush_descq;
+
+ /* Post a flush command */
+ EFX_POPULATE_OWORD_2(rx_flush_descq,
+ RX_FLUSH_DESCQ_CMD, 1,
+ RX_FLUSH_DESCQ, rx_queue->queue);
+ falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
+ msleep(FALCON_FLUSH_TIMEOUT);
+
+ if (EFX_WORKAROUND_7803(efx))
+ return 0;
+
+ /* Look for a flush completed event */
+ read_ptr = channel->eventq_read_ptr;
+ for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+ efx_qword_t *event = falcon_event(channel, read_ptr);
+ int ev_code, ev_sub_code, ev_queue, ev_failed;
+ if (!falcon_event_present(event))
+ break;
+
+ ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID);
+ ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL);
+
+ if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) &&
+ (ev_queue == rx_queue->queue)) {
+ if (ev_failed) {
+ EFX_INFO(efx, "rx queue %d flush command "
+ "failed\n", rx_queue->queue);
+ return -EAGAIN;
+ } else {
+ EFX_LOG(efx, "rx queue %d flush command "
+ "succesful\n", rx_queue->queue);
+ return 0;
+ }
+ }
+
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ }
+
+ if (EFX_WORKAROUND_11557(efx)) {
+ efx_oword_t reg;
+ int enabled;
+
+ falcon_read_table(efx, &reg, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+ enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN);
+ if (!enabled) {
+ EFX_LOG(efx, "rx queue %d disabled without a "
+ "flush event seen\n", rx_queue->queue);
+ return 0;
+ }
+ }
+
+ EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue);
+ return -ETIMEDOUT;
+}
+
+void falcon_fini_rx(struct efx_rx_queue *rx_queue)
+{
+ efx_oword_t rx_desc_ptr;
+ struct efx_nic *efx = rx_queue->efx;
+ int i, rc;
+
+ /* Try and flush the rx queue. This may need to be repeated */
+ for (i = 0; i < 5; i++) {
+ rc = falcon_flush_rx_queue(rx_queue);
+ if (rc == -EAGAIN)
+ continue;
+ break;
+ }
+ if (rc)
+ EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
+
+ /* Remove RX descriptor ring from card */
+ EFX_ZERO_OWORD(rx_desc_ptr);
+ falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+
+ /* Unpin RX descriptor ring */
+ falcon_fini_special_buffer(efx, &rx_queue->rxd);
+}
+
+/* Free buffers backing RX queue */
+void falcon_remove_rx(struct efx_rx_queue *rx_queue)
+{
+ falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
+}
+
+/**************************************************************************
+ *
+ * Falcon event queue processing
+ * Event queues are processed by per-channel tasklets.
+ *
+ **************************************************************************/
+
+/* Update a channel's event queue's read pointer (RPTR) register
+ *
+ * This writes the EVQ_RPTR_REG register for the specified channel's
+ * event queue.
+ *
+ * Note that EVQ_RPTR_REG contains the index of the "last read" event,
+ * whereas channel->eventq_read_ptr contains the index of the "next to
+ * read" event.
+ */
+void falcon_eventq_read_ack(struct efx_channel *channel)
+{
+ efx_dword_t reg;
+ struct efx_nic *efx = channel->efx;
+
+ EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
+ falcon_writel_table(efx, &reg, efx->type->evq_rptr_tbl_base,
+ channel->evqnum);
+}
+
+/* Use HW to insert a SW defined event */
+void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ efx_oword_t drv_ev_reg;
+
+ EFX_POPULATE_OWORD_2(drv_ev_reg,
+ DRV_EV_QID, channel->evqnum,
+ DRV_EV_DATA,
+ EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
+ falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
+}
+
+/* Handle a transmit completion event
+ *
+ * Falcon batches TX completion events; the message we receive is of
+ * the form "complete all TX events up to this index".
+ */
+static inline void falcon_handle_tx_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ unsigned int tx_ev_desc_ptr;
+ unsigned int tx_ev_q_label;
+ struct efx_tx_queue *tx_queue;
+ struct efx_nic *efx = channel->efx;
+
+ if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) {
+ /* Transmit completion */
+ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ tx_queue = &efx->tx_queue[tx_ev_q_label];
+ efx_xmit_done(tx_queue, tx_ev_desc_ptr);
+ } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
+ /* Rewrite the FIFO write pointer */
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ tx_queue = &efx->tx_queue[tx_ev_q_label];
+
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_lock(efx->net_dev);
+ falcon_notify_tx_desc(tx_queue);
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_unlock(efx->net_dev);
+ } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
+ EFX_WORKAROUND_10727(efx)) {
+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
+ } else {
+ EFX_ERR(efx, "channel %d unexpected TX event "
+ EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+ }
+}
+
+/* Check received packet's destination MAC address. */
+static int check_dest_mac(struct efx_rx_queue *rx_queue,
+ const efx_qword_t *event)
+{
+ struct efx_rx_buffer *rx_buf;
+ struct efx_nic *efx = rx_queue->efx;
+ int rx_ev_desc_ptr;
+ struct ethhdr *eh;
+
+ if (efx->promiscuous)
+ return 1;
+
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
+ rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
+ eh = (struct ethhdr *)rx_buf->data;
+ if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
+ return 0;
+ return 1;
+}
+
+/* Detect errors included in the rx_evt_pkt_ok bit. */
+static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
+ const efx_qword_t *event,
+ unsigned *rx_ev_pkt_ok,
+ int *discard, int byte_count)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+ unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
+ unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
+ unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
+ unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+ int snap, non_ip;
+
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC);
+ rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE);
+ rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
+ RX_EV_BUF_OWNER_ID_ERR);
+ rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR);
+ rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
+ RX_EV_IP_HDR_CHKSUM_ERR);
+ rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
+ RX_EV_TCP_UDP_CHKSUM_ERR);
+ rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
+ rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
+ rx_ev_drib_nib = ((FALCON_REV(efx) >= FALCON_REV_B0) ?
+ 0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
+ rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
+
+ /* Every error apart from tobe_disc and pause_frm */
+ rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
+ rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
+ rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
+
+ snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
+ (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
+ non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
+
+ /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
+ * length field of an LLC frame, which sets TOBE_DISC. We could set
+ * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
+ * protect the RX block).
+ *
+ * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
+ * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
+ * LLC can't encapsulate IP, so by definition
+ * these packets are NON_IP.
+ *
+ * Unicast mismatch will also cause TOBE_DISC, so the driver needs
+ * to check this.
+ */
+ if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
+ /* If all the other flags are zero then we can state the
+ * entire packet is ok, which will flag to the kernel not
+ * to recalculate checksums.
+ */
+ if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
+ *rx_ev_pkt_ok = 1;
+
+ rx_ev_tobe_disc = 0;
+
+ /* TOBE_DISC is set for unicast mismatch. But given that
+ * we can't trust TOBE_DISC here, we must validate the dest
+ * MAC address ourselves.
+ */
+ if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
+ rx_ev_tobe_disc = 1;
+ }
+
+ /* Count errors that are not in MAC stats. */
+ if (rx_ev_frm_trunc)
+ ++rx_queue->channel->n_rx_frm_trunc;
+ else if (rx_ev_tobe_disc)
+ ++rx_queue->channel->n_rx_tobe_disc;
+ else if (rx_ev_ip_hdr_chksum_err)
+ ++rx_queue->channel->n_rx_ip_hdr_chksum_err;
+ else if (rx_ev_tcp_udp_chksum_err)
+ ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
+ if (rx_ev_ip_frag_err)
+ ++rx_queue->channel->n_rx_ip_frag_err;
+
+ /* The frame must be discarded if any of these are true. */
+ *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
+ rx_ev_tobe_disc | rx_ev_pause_frm);
+
+ /* TOBE_DISC is expected on unicast mismatches; don't print out an
+ * error message. FRM_TRUNC indicates RXDP dropped the packet due
+ * to a FIFO overflow.
+ */
+#ifdef EFX_ENABLE_DEBUG
+ if (rx_ev_other_err) {
+ EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
+ EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
+ rx_queue->queue, EFX_QWORD_VAL(*event),
+ rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
+ rx_ev_ip_hdr_chksum_err ?
+ " [IP_HDR_CHKSUM_ERR]" : "",
+ rx_ev_tcp_udp_chksum_err ?
+ " [TCP_UDP_CHKSUM_ERR]" : "",
+ rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
+ rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
+ rx_ev_drib_nib ? " [DRIB_NIB]" : "",
+ rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
+ rx_ev_pause_frm ? " [PAUSE]" : "",
+ snap ? " [SNAP/LLC]" : "");
+ }
+#endif
+
+ if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) &&
+ efx->phy_type == PHY_TYPE_10XPRESS))
+ tenxpress_crc_err(efx);
+}
+
+/* Handle receive events that are not in-order. */
+static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
+ unsigned index)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned expected, dropped;
+
+ expected = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ dropped = ((index + FALCON_RXD_RING_SIZE - expected) &
+ FALCON_RXD_RING_MASK);
+ EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
+ dropped, index, expected);
+
+ efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+}
+
+/* Handle a packet received event
+ *
+ * Falcon silicon gives a "discard" flag if it's a unicast packet with the
+ * wrong destination address
+ * Also "is multicast" and "matches multicast filter" flags can be used to
+ * discard non-matching multicast packets.
+ */
+static inline int falcon_handle_rx_event(struct efx_channel *channel,
+ const efx_qword_t *event)
+{
+ unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
+ unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
+ unsigned expected_ptr;
+ int discard = 0, checksummed;
+ struct efx_rx_queue *rx_queue;
+ struct efx_nic *efx = channel->efx;
+
+ /* Basic packet information */
+ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT);
+ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK);
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
+ WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
+ WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
+
+ rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL);
+ rx_queue = &efx->rx_queue[rx_ev_q_label];
+
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
+ expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ if (unlikely(rx_ev_desc_ptr != expected_ptr)) {
+ falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
+ return rx_ev_q_label;
+ }
+
+ if (likely(rx_ev_pkt_ok)) {
+ /* If packet is marked as OK and packet type is TCP/IPv4 or
+ * UDP/IPv4, then we can rely on the hardware checksum.
+ */
+ checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
+ } else {
+ falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
+ &discard, rx_ev_byte_cnt);
+ checksummed = 0;
+ }
+
+ /* Detect multicast packets that didn't match the filter */
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ if (rx_ev_mcast_pkt) {
+ unsigned int rx_ev_mcast_hash_match =
+ EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
+
+ if (unlikely(!rx_ev_mcast_hash_match))
+ discard = 1;
+ }
+
+ /* Handle received packet */
+ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
+ checksummed, discard);
+
+ return rx_ev_q_label;
+}
+
+/* Global events are basically PHY events */
+static void falcon_handle_global_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ int is_phy_event = 0, handled = 0;
+
+ /* Check for interrupt on either port. Some boards have a
+ * single PHY wired to the interrupt line for port 1. */
+ if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
+ EFX_QWORD_FIELD(*event, XG_PHY_INTR))
+ is_phy_event = 1;
+
+ if ((FALCON_REV(efx) >= FALCON_REV_B0) &&
+ EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
+ is_phy_event = 1;
+
+ if (is_phy_event) {
+ efx->phy_op->clear_interrupt(efx);
+ queue_work(efx->workqueue, &efx->reconfigure_work);
+ handled = 1;
+ }
+
+ if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
+ EFX_ERR(efx, "channel %d seen global RX_RESET "
+ "event. Resetting.\n", channel->channel);
+
+ atomic_inc(&efx->rx_reset);
+ efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+ handled = 1;
+ }
+
+ if (!handled)
+ EFX_ERR(efx, "channel %d unknown global event "
+ EFX_QWORD_FMT "\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+}
+
+static void falcon_handle_driver_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned int ev_sub_code;
+ unsigned int ev_sub_data;
+
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA);
+
+ switch (ev_sub_code) {
+ case TX_DESCQ_FLS_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
+ channel->channel, ev_sub_data);
+ break;
+ case RX_DESCQ_FLS_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
+ channel->channel, ev_sub_data);
+ break;
+ case EVQ_INIT_DONE_EV_DECODE:
+ EFX_LOG(efx, "channel %d EVQ %d initialised\n",
+ channel->channel, ev_sub_data);
+ break;
+ case SRM_UPD_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d SRAM update done\n",
+ channel->channel);
+ break;
+ case WAKE_UP_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
+ channel->channel, ev_sub_data);
+ break;
+ case TIMER_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
+ channel->channel, ev_sub_data);
+ break;
+ case RX_RECOVERY_EV_DECODE:
+ EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
+ "Resetting.\n", channel->channel);
+ atomic_inc(&efx->rx_reset);
+ efx_schedule_reset(efx,
+ EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY :
+ RESET_TYPE_DISABLE);
+ break;
+ case RX_DSC_ERROR_EV_DECODE:
+ EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
+ " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
+ break;
+ case TX_DSC_ERROR_EV_DECODE:
+ EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
+ " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
+ break;
+ default:
+ EFX_TRACE(efx, "channel %d unknown driver event code %d "
+ "data %04x\n", channel->channel, ev_sub_code,
+ ev_sub_data);
+ break;
+ }
+}
+
+int falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
+{
+ unsigned int read_ptr;
+ efx_qword_t event, *p_event;
+ int ev_code;
+ int rxq;
+ int rxdmaqs = 0;
+
+ read_ptr = channel->eventq_read_ptr;
+
+ do {
+ p_event = falcon_event(channel, read_ptr);
+ event = *p_event;
+
+ if (!falcon_event_present(&event))
+ /* End of events */
+ break;
+
+ EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
+ channel->channel, EFX_QWORD_VAL(event));
+
+ /* Clear this event by marking it all ones */
+ EFX_SET_QWORD(*p_event);
+
+ ev_code = EFX_QWORD_FIELD(event, EV_CODE);
+
+ switch (ev_code) {
+ case RX_IP_EV_DECODE:
+ rxq = falcon_handle_rx_event(channel, &event);
+ rxdmaqs |= (1 << rxq);
+ (*rx_quota)--;
+ break;
+ case TX_IP_EV_DECODE:
+ falcon_handle_tx_event(channel, &event);
+ break;
+ case DRV_GEN_EV_DECODE:
+ channel->eventq_magic
+ = EFX_QWORD_FIELD(event, EVQ_MAGIC);
+ EFX_LOG(channel->efx, "channel %d received generated "
+ "event "EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(event));
+ break;
+ case GLOBAL_EV_DECODE:
+ falcon_handle_global_event(channel, &event);
+ break;
+ case DRIVER_EV_DECODE:
+ falcon_handle_driver_event(channel, &event);
+ break;
+ default:
+ EFX_ERR(channel->efx, "channel %d unknown event type %d"
+ " (data " EFX_QWORD_FMT ")\n", channel->channel,
+ ev_code, EFX_QWORD_VAL(event));
+ }
+
+ /* Increment read pointer */
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+
+ } while (*rx_quota);
+
+ channel->eventq_read_ptr = read_ptr;
+ return rxdmaqs;
+}
+
+void falcon_set_int_moderation(struct efx_channel *channel)
+{
+ efx_dword_t timer_cmd;
+ struct efx_nic *efx = channel->efx;
+
+ /* Set timer register */
+ if (channel->irq_moderation) {
+ /* Round to resolution supported by hardware. The value we
+ * program is based at 0. So actual interrupt moderation
+ * achieved is ((x + 1) * res).
+ */
+ unsigned int res = 5;
+ channel->irq_moderation -= (channel->irq_moderation % res);
+ if (channel->irq_moderation < res)
+ channel->irq_moderation = res;
+ EFX_POPULATE_DWORD_2(timer_cmd,
+ TIMER_MODE, TIMER_MODE_INT_HLDOFF,
+ TIMER_VAL,
+ (channel->irq_moderation / res) - 1);
+ } else {
+ EFX_POPULATE_DWORD_2(timer_cmd,
+ TIMER_MODE, TIMER_MODE_DIS,
+ TIMER_VAL, 0);
+ }
+ falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
+ channel->evqnum);
+
+}
+
+/* Allocate buffer table entries for event queue */
+int falcon_probe_eventq(struct efx_channel *channel)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned int evq_size;
+
+ evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t);
+ return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
+}
+
+int falcon_init_eventq(struct efx_channel *channel)
+{
+ efx_oword_t evq_ptr;
+ struct efx_nic *efx = channel->efx;
+ int rc;
+
+ EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
+ channel->channel, channel->eventq.index,
+ channel->eventq.index + channel->eventq.entries - 1);
+
+ /* Pin event queue buffer */
+ rc = falcon_init_special_buffer(efx, &channel->eventq);
+ if (rc)
+ return rc;
+
+ /* Fill event queue with all ones (i.e. empty events) */
+ memset(channel->eventq.addr, 0xff, channel->eventq.len);
+
+ /* Push event queue to card */
+ EFX_POPULATE_OWORD_3(evq_ptr,
+ EVQ_EN, 1,
+ EVQ_SIZE, FALCON_EVQ_ORDER,
+ EVQ_BUF_BASE_ID, channel->eventq.index);
+ falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->evqnum);
+
+ falcon_set_int_moderation(channel);
+
+ return 0;
+}
+
+void falcon_fini_eventq(struct efx_channel *channel)
+{
+ efx_oword_t eventq_ptr;
+ struct efx_nic *efx = channel->efx;
+
+ /* Remove event queue from card */
+ EFX_ZERO_OWORD(eventq_ptr);
+ falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->evqnum);
+
+ /* Unpin event queue */
+ falcon_fini_special_buffer(efx, &channel->eventq);
+}
+
+/* Free buffers backing event queue */
+void falcon_remove_eventq(struct efx_channel *channel)
+{
+ falcon_free_special_buffer(channel->efx, &channel->eventq);
+}
+
+
+/* Generates a test event on the event queue. A subsequent call to
+ * process_eventq() should pick up the event and place the value of
+ * "magic" into channel->eventq_magic;
+ */
+void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
+{
+ efx_qword_t test_event;
+
+ EFX_POPULATE_QWORD_2(test_event,
+ EV_CODE, DRV_GEN_EV_DECODE,
+ EVQ_MAGIC, magic);
+ falcon_generate_event(channel, &test_event);
+}
+
+
+/**************************************************************************
+ *
+ * Falcon hardware interrupts
+ * The hardware interrupt handler does very little work; all the event
+ * queue processing is carried out by per-channel tasklets.
+ *
+ **************************************************************************/
+
+/* Enable/disable/generate Falcon interrupts */
+static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
+ int force)
+{
+ efx_oword_t int_en_reg_ker;
+
+ EFX_POPULATE_OWORD_2(int_en_reg_ker,
+ KER_INT_KER, force,
+ DRV_INT_EN_KER, enabled);
+ falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER);
+}
+
+void falcon_enable_interrupts(struct efx_nic *efx)
+{
+ efx_oword_t int_adr_reg_ker;
+ struct efx_channel *channel;
+
+ EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
+ wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
+
+ /* Program address */
+ EFX_POPULATE_OWORD_2(int_adr_reg_ker,
+ NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx),
+ INT_ADR_KER, efx->irq_status.dma_addr);
+ falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER);
+
+ /* Enable interrupts */
+ falcon_interrupts(efx, 1, 0);
+
+ /* Force processing of all the channels to get the EVQ RPTRs up to
+ date */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ efx_schedule_channel(channel);
+}
+
+void falcon_disable_interrupts(struct efx_nic *efx)
+{
+ /* Disable interrupts */
+ falcon_interrupts(efx, 0, 0);
+}
+
+/* Generate a Falcon test interrupt
+ * Interrupt must already have been enabled, otherwise nasty things
+ * may happen.
+ */
+void falcon_generate_interrupt(struct efx_nic *efx)
+{
+ falcon_interrupts(efx, 1, 1);
+}
+
+/* Acknowledge a legacy interrupt from Falcon
+ *
+ * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
+ *
+ * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
+ * BIU. Interrupt acknowledge is read sensitive so must write instead
+ * (then read to ensure the BIU collector is flushed)
+ *
+ * NB most hardware supports MSI interrupts
+ */
+static inline void falcon_irq_ack_a1(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e);
+ falcon_writel(efx, &reg, INT_ACK_REG_KER_A1);
+ falcon_readl(efx, &reg, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1);
+}
+
+/* Process a fatal interrupt
+ * Disable bus mastering ASAP and schedule a reset
+ */
+static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ efx_oword_t fatal_intr;
+ int error, mem_perr;
+ static int n_int_errors;
+
+ falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
+ error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
+
+ EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
+ EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
+ EFX_OWORD_VAL(fatal_intr),
+ error ? "disabling bus mastering" : "no recognised error");
+ if (error == 0)
+ goto out;
+
+ /* If this is a memory parity error dump which blocks are offending */
+ mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER);
+ if (mem_perr) {
+ efx_oword_t reg;
+ falcon_read(efx, &reg, MEM_STAT_REG_KER);
+ EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
+ EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
+ }
+
+ /* Disable DMA bus mastering on both devices */
+ pci_disable_device(efx->pci_dev);
+ if (FALCON_IS_DUAL_FUNC(efx))
+ pci_disable_device(nic_data->pci_dev2);
+
+ if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
+ EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
+ efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
+ } else {
+ EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
+ "NIC will be disabled\n");
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+/* Handle a legacy interrupt from Falcon
+ * Acknowledges the interrupt and schedule event queue processing.
+ */
+static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
+{
+ struct efx_nic *efx = (struct efx_nic *)dev_id;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_channel *channel;
+ efx_dword_t reg;
+ u32 queues;
+ int syserr;
+
+ /* Read the ISR which also ACKs the interrupts */
+ falcon_readl(efx, &reg, INT_ISR0_B0);
+ queues = EFX_EXTRACT_DWORD(reg, 0, 31);
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ if (queues == 0)
+ return IRQ_NONE;
+
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+
+ /* Schedule processing of any interrupting queues */
+ channel = &efx->channel[0];
+ while (queues) {
+ if (queues & 0x01)
+ efx_schedule_channel(channel);
+ channel++;
+ queues >>= 1;
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
+{
+ struct efx_nic *efx = (struct efx_nic *)dev_id;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_channel *channel;
+ int syserr;
+ int queues;
+
+ /* Check to see if this is our interrupt. If it isn't, we
+ * exit without having touched the hardware.
+ */
+ if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
+ EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
+ raw_smp_processor_id());
+ return IRQ_NONE;
+ }
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ /* Determine interrupting queues, clear interrupt status
+ * register and acknowledge the device interrupt.
+ */
+ BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
+ queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
+ EFX_ZERO_OWORD(*int_ker);
+ wmb(); /* Ensure the vector is cleared before interrupt ack */
+ falcon_irq_ack_a1(efx);
+
+ /* Schedule processing of any interrupting queues */
+ channel = &efx->channel[0];
+ while (queues) {
+ if (queues & 0x01)
+ efx_schedule_channel(channel);
+ channel++;
+ queues >>= 1;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Handle an MSI interrupt from Falcon
+ *
+ * Handle an MSI hardware interrupt. This routine schedules event
+ * queue processing. No interrupt acknowledgement cycle is necessary.
+ * Also, we never need to check that the interrupt is for us, since
+ * MSI interrupts cannot be shared.
+ */
+static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
+{
+ struct efx_channel *channel = (struct efx_channel *)dev_id;
+ struct efx_nic *efx = channel->efx;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ int syserr;
+
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ /* Schedule processing of the channel */
+ efx_schedule_channel(channel);
+
+ return IRQ_HANDLED;
+}
+
+
+/* Setup RSS indirection table.
+ * This maps from the hash value of the packet to RXQ
+ */
+static void falcon_setup_rss_indir_table(struct efx_nic *efx)
+{
+ int i = 0;
+ unsigned long offset;
+ efx_dword_t dword;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ for (offset = RX_RSS_INDIR_TBL_B0;
+ offset < RX_RSS_INDIR_TBL_B0 + 0x800;
+ offset += 0x10) {
+ EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
+ i % efx->rss_queues);
+ falcon_writel(efx, &dword, offset);
+ i++;
+ }
+}
+
+/* Hook interrupt handler(s)
+ * Try MSI and then legacy interrupts.
+ */
+int falcon_init_interrupt(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ if (!EFX_INT_MODE_USE_MSI(efx)) {
+ irq_handler_t handler;
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ handler = falcon_legacy_interrupt_b0;
+ else
+ handler = falcon_legacy_interrupt_a1;
+
+ rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
+ efx->name, efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
+ efx->pci_dev->irq);
+ goto fail1;
+ }
+ return 0;
+ }
+
+ /* Hook MSI or MSI-X interrupt */
+ efx_for_each_channel_with_interrupt(channel, efx) {
+ rc = request_irq(channel->irq, falcon_msi_interrupt,
+ IRQF_PROBE_SHARED, /* Not shared */
+ efx->name, channel);
+ if (rc) {
+ EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
+ goto fail2;
+ }
+ }
+
+ return 0;
+
+ fail2:
+ efx_for_each_channel_with_interrupt(channel, efx)
+ free_irq(channel->irq, channel);
+ fail1:
+ return rc;
+}
+
+void falcon_fini_interrupt(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ efx_oword_t reg;
+
+ /* Disable MSI/MSI-X interrupts */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ if (channel->irq)
+ free_irq(channel->irq, channel);
+
+ /* ACK legacy interrupt */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ falcon_read(efx, &reg, INT_ISR0_B0);
+ else
+ falcon_irq_ack_a1(efx);
+
+ /* Disable legacy interrupt */
+ if (efx->legacy_irq)
+ free_irq(efx->legacy_irq, efx);
+}
+
+/**************************************************************************
+ *
+ * EEPROM/flash
+ *
+ **************************************************************************
+ */
+
+#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
+
+/* Wait for SPI command completion */
+static int falcon_spi_wait(struct efx_nic *efx)
+{
+ efx_oword_t reg;
+ int cmd_en, timer_active;
+ int count;
+
+ count = 0;
+ do {
+ falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
+ cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
+ timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
+ if (!cmd_en && !timer_active)
+ return 0;
+ udelay(10);
+ } while (++count < 10000); /* wait upto 100msec */
+ EFX_ERR(efx, "timed out waiting for SPI\n");
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command,
+ unsigned int address, unsigned int addr_len,
+ void *data, unsigned int len)
+{
+ efx_oword_t reg;
+ int rc;
+
+ BUG_ON(len > FALCON_SPI_MAX_LEN);
+
+ /* Check SPI not currently being accessed */
+ rc = falcon_spi_wait(efx);
+ if (rc)
+ return rc;
+
+ /* Program address register */
+ EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
+ falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+
+ /* Issue read command */
+ EFX_POPULATE_OWORD_7(reg,
+ EE_SPI_HCMD_CMD_EN, 1,
+ EE_SPI_HCMD_SF_SEL, device_id,
+ EE_SPI_HCMD_DABCNT, len,
+ EE_SPI_HCMD_READ, EE_SPI_READ,
+ EE_SPI_HCMD_DUBCNT, 0,
+ EE_SPI_HCMD_ADBCNT, addr_len,
+ EE_SPI_HCMD_ENC, command);
+ falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
+
+ /* Wait for read to complete */
+ rc = falcon_spi_wait(efx);
+ if (rc)
+ return rc;
+
+ /* Read data */
+ falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
+ memcpy(data, &reg, len);
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * MAC wrapper
+ *
+ **************************************************************************
+ */
+void falcon_drain_tx_fifo(struct efx_nic *efx)
+{
+ efx_oword_t temp;
+ int count;
+
+ if ((FALCON_REV(efx) < FALCON_REV_B0) ||
+ (efx->loopback_mode != LOOPBACK_NONE))
+ return;
+
+ falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
+ /* There is no point in draining more than once */
+ if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ return;
+
+ /* MAC stats will fail whilst the TX fifo is draining. Serialise
+ * the drain sequence with the statistics fetch */
+ spin_lock(&efx->stats_lock);
+
+ EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
+ falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
+
+ /* Reset the MAC and EM block. */
+ falcon_read(efx, &temp, GLB_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
+ EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
+ EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
+ falcon_write(efx, &temp, GLB_CTL_REG_KER);
+
+ count = 0;
+ while (1) {
+ falcon_read(efx, &temp, GLB_CTL_REG_KER);
+ if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
+ !EFX_OWORD_FIELD(temp, RST_XGRX) &&
+ !EFX_OWORD_FIELD(temp, RST_EM)) {
+ EFX_LOG(efx, "Completed MAC reset after %d loops\n",
+ count);
+ break;
+ }
+ if (count > 20) {
+ EFX_ERR(efx, "MAC reset failed\n");
+ break;
+ }
+ count++;
+ udelay(10);
+ }
+
+ spin_unlock(&efx->stats_lock);
+
+ /* If we've reset the EM block and the link is up, then
+ * we'll have to kick the XAUI link so the PHY can recover */
+ if (efx->link_up && EFX_WORKAROUND_5147(efx))
+ falcon_reset_xaui(efx);
+}
+
+void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+{
+ efx_oword_t temp;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ /* Isolate the MAC -> RX */
+ falcon_read(efx, &temp, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
+ falcon_write(efx, &temp, RX_CFG_REG_KER);
+
+ if (!efx->link_up)
+ falcon_drain_tx_fifo(efx);
+}
+
+void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
+{
+ efx_oword_t reg;
+ int link_speed;
+ unsigned int tx_fc;
+
+ if (efx->link_options & GM_LPA_10000)
+ link_speed = 0x3;
+ else if (efx->link_options & GM_LPA_1000)
+ link_speed = 0x2;
+ else if (efx->link_options & GM_LPA_100)
+ link_speed = 0x1;
+ else
+ link_speed = 0x0;
+ /* MAC_LINK_STATUS controls MAC backpressure but doesn't work
+ * as advertised. Disable to ensure packets are not
+ * indefinitely held and TX queue can be flushed at any point
+ * while the link is down. */
+ EFX_POPULATE_OWORD_5(reg,
+ MAC_XOFF_VAL, 0xffff /* max pause time */,
+ MAC_BCAD_ACPT, 1,
+ MAC_UC_PROM, efx->promiscuous,
+ MAC_LINK_STATUS, 1, /* always set */
+ MAC_SPEED, link_speed);
+ /* On B0, MAC backpressure can be disabled and packets get
+ * discarded. */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
+ !efx->link_up);
+ }
+
+ falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
+
+ /* Restore the multicast hash registers. */
+ falcon_set_multicast_hash(efx);
+
+ /* Transmission of pause frames when RX crosses the threshold is
+ * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
+ * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
+ tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+ falcon_read(efx, &reg, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
+
+ /* Unisolate the MAC -> RX */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
+ falcon_write(efx, &reg, RX_CFG_REG_KER);
+}
+
+int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
+{
+ efx_oword_t reg;
+ u32 *dma_done;
+ int i;
+
+ if (disable_dma_stats)
+ return 0;
+
+ /* Statistics fetch will fail if the MAC is in TX drain */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ efx_oword_t temp;
+ falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
+ if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ return 0;
+ }
+
+ dma_done = (efx->stats_buffer.addr + done_offset);
+ *dma_done = FALCON_STATS_NOT_DONE;
+ wmb(); /* ensure done flag is clear */
+
+ /* Initiate DMA transfer of stats */
+ EFX_POPULATE_OWORD_2(reg,
+ MAC_STAT_DMA_CMD, 1,
+ MAC_STAT_DMA_ADR,
+ efx->stats_buffer.dma_addr);
+ falcon_write(efx, &reg, MAC0_STAT_DMA_REG_KER);
+
+ /* Wait for transfer to complete */
+ for (i = 0; i < 400; i++) {
+ if (*(volatile u32 *)dma_done == FALCON_STATS_DONE)
+ return 0;
+ udelay(10);
+ }
+
+ EFX_ERR(efx, "timed out waiting for statistics\n");
+ return -ETIMEDOUT;
+}
+
+/**************************************************************************
+ *
+ * PHY access via GMII
+ *
+ **************************************************************************
+ */
+
+/* Use the top bit of the MII PHY id to indicate the PHY type
+ * (1G/10G), with the remaining bits as the actual PHY id.
+ *
+ * This allows us to avoid leaking information from the mii_if_info
+ * structure into other data structures.
+ */
+#define FALCON_PHY_ID_ID_WIDTH EFX_WIDTH(MD_PRT_DEV_ADR)
+#define FALCON_PHY_ID_ID_MASK ((1 << FALCON_PHY_ID_ID_WIDTH) - 1)
+#define FALCON_PHY_ID_WIDTH (FALCON_PHY_ID_ID_WIDTH + 1)
+#define FALCON_PHY_ID_MASK ((1 << FALCON_PHY_ID_WIDTH) - 1)
+#define FALCON_PHY_ID_10G (1 << (FALCON_PHY_ID_WIDTH - 1))
+
+
+/* Packing the clause 45 port and device fields into a single value */
+#define MD_PRT_ADR_COMP_LBN (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN)
+#define MD_PRT_ADR_COMP_WIDTH MD_PRT_ADR_WIDTH
+#define MD_DEV_ADR_COMP_LBN 0
+#define MD_DEV_ADR_COMP_WIDTH MD_DEV_ADR_WIDTH
+
+
+/* Wait for GMII access to complete */
+static int falcon_gmii_wait(struct efx_nic *efx)
+{
+ efx_dword_t md_stat;
+ int count;
+
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
+ if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
+ if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
+ EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) {
+ EFX_ERR(efx, "error from GMII access "
+ EFX_DWORD_FMT"\n",
+ EFX_DWORD_VAL(md_stat));
+ return -EIO;
+ }
+ return 0;
+ }
+ udelay(10);
+ }
+ EFX_ERR(efx, "timed out waiting for GMII\n");
+ return -ETIMEDOUT;
+}
+
+/* Writes a GMII register of a PHY connected to Falcon using MDIO. */
+static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
+ int addr, int value)
+{
+ struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
+ efx_oword_t reg;
+
+ /* The 'generic' prt/dev packing in mdio_10g.h is conveniently
+ * chosen so that the only current user, Falcon, can take the
+ * packed value and use them directly.
+ * Fail to build if this assumption is broken.
+ */
+ BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G);
+ BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH);
+ BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN);
+ BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN);
+
+ if (phy_id2 == PHY_ADDR_INVALID)
+ return;
+
+ /* See falcon_mdio_read for an explanation. */
+ if (!(phy_id & FALCON_PHY_ID_10G)) {
+ int mmd = ffs(efx->phy_op->mmds) - 1;
+ EFX_TRACE(efx, "Fixing erroneous clause22 write\n");
+ phy_id2 = mdio_clause45_pack(phy_id2, mmd)
+ & FALCON_PHY_ID_ID_MASK;
+ }
+
+ EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id,
+ addr, value);
+
+ spin_lock_bh(&efx->phy_lock);
+
+ /* Check MII not currently being accessed */
+ if (falcon_gmii_wait(efx) != 0)
+ goto out;
+
+ /* Write the address/ID register */
+ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
+ falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+
+ EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2);
+ falcon_write(efx, &reg, MD_ID_REG_KER);
+
+ /* Write data */
+ EFX_POPULATE_OWORD_1(reg, MD_TXD, value);
+ falcon_write(efx, &reg, MD_TXD_REG_KER);
+
+ EFX_POPULATE_OWORD_2(reg,
+ MD_WRC, 1,
+ MD_GC, 0);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+
+ /* Wait for data to be written */
+ if (falcon_gmii_wait(efx) != 0) {
+ /* Abort the write operation */
+ EFX_POPULATE_OWORD_2(reg,
+ MD_WRC, 0,
+ MD_GC, 1);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+ udelay(10);
+ }
+
+ out:
+ spin_unlock_bh(&efx->phy_lock);
+}
+
+/* Reads a GMII register from a PHY connected to Falcon. If no value
+ * could be read, -1 will be returned. */
+static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
+{
+ struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
+ efx_oword_t reg;
+ int value = -1;
+
+ if (phy_addr == PHY_ADDR_INVALID)
+ return -1;
+
+ /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G)
+ * but the generic Linux code does not make any distinction or have
+ * any state for this.
+ * We spot the case where someone tried to talk 22 to a 45 PHY and
+ * redirect the request to the lowest numbered MMD as a clause45
+ * request. This is enough to allow simple queries like id and link
+ * state to succeed. TODO: We may need to do more in future.
+ */
+ if (!(phy_id & FALCON_PHY_ID_10G)) {
+ int mmd = ffs(efx->phy_op->mmds) - 1;
+ EFX_TRACE(efx, "Fixing erroneous clause22 read\n");
+ phy_addr = mdio_clause45_pack(phy_addr, mmd)
+ & FALCON_PHY_ID_ID_MASK;
+ }
+
+ spin_lock_bh(&efx->phy_lock);
+
+ /* Check MII not currently being accessed */
+ if (falcon_gmii_wait(efx) != 0)
+ goto out;
+
+ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
+ falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+
+ EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr);
+ falcon_write(efx, &reg, MD_ID_REG_KER);
+
+ /* Request data to be read */
+ EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+
+ /* Wait for data to become available */
+ value = falcon_gmii_wait(efx);
+ if (value == 0) {
+ falcon_read(efx, &reg, MD_RXD_REG_KER);
+ value = EFX_OWORD_FIELD(reg, MD_RXD);
+ EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n",
+ phy_id, addr, value);
+ } else {
+ /* Abort the read operation */
+ EFX_POPULATE_OWORD_2(reg,
+ MD_RIC, 0,
+ MD_GC, 1);
+ falcon_write(efx, &reg, MD_CS_REG_KER);
+
+ EFX_LOG(efx, "read from GMII 0x%x register %02x, got "
+ "error %d\n", phy_id, addr, value);
+ }
+
+ out:
+ spin_unlock_bh(&efx->phy_lock);
+
+ return value;
+}
+
+static void falcon_init_mdio(struct mii_if_info *gmii)
+{
+ gmii->mdio_read = falcon_mdio_read;
+ gmii->mdio_write = falcon_mdio_write;
+ gmii->phy_id_mask = FALCON_PHY_ID_MASK;
+ gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1);
+}
+
+static int falcon_probe_phy(struct efx_nic *efx)
+{
+ switch (efx->phy_type) {
+ case PHY_TYPE_10XPRESS:
+ efx->phy_op = &falcon_tenxpress_phy_ops;
+ break;
+ case PHY_TYPE_XFP:
+ efx->phy_op = &falcon_xfp_phy_ops;
+ break;
+ default:
+ EFX_ERR(efx, "Unknown PHY type %d\n",
+ efx->phy_type);
+ return -1;
+ }
+
+ efx->loopback_modes = LOOPBACKS_10G_INTERNAL | efx->phy_op->loopbacks;
+ return 0;
+}
+
+/* This call is responsible for hooking in the MAC and PHY operations */
+int falcon_probe_port(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Hook in PHY operations table */
+ rc = falcon_probe_phy(efx);
+ if (rc)
+ return rc;
+
+ /* Set up GMII structure for PHY */
+ efx->mii.supports_gmii = 1;
+ falcon_init_mdio(&efx->mii);
+
+ /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ efx->flow_control = EFX_FC_RX | EFX_FC_TX;
+ else
+ efx->flow_control = EFX_FC_RX;
+
+ /* Allocate buffer for stats */
+ rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
+ FALCON_MAC_STATS_SIZE);
+ if (rc)
+ return rc;
+ EFX_LOG(efx, "stats buffer at %llx (virt %p phys %lx)\n",
+ (unsigned long long)efx->stats_buffer.dma_addr,
+ efx->stats_buffer.addr,
+ virt_to_phys(efx->stats_buffer.addr));
+
+ return 0;
+}
+
+void falcon_remove_port(struct efx_nic *efx)
+{
+ falcon_free_buffer(efx, &efx->stats_buffer);
+}
+
+/**************************************************************************
+ *
+ * Multicast filtering
+ *
+ **************************************************************************
+ */
+
+void falcon_set_multicast_hash(struct efx_nic *efx)
+{
+ union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+
+ /* Broadcast packets go through the multicast hash filter.
+ * ether_crc_le() of the broadcast address is 0xbe2612ff
+ * so we always add bit 0xff to the mask.
+ */
+ set_bit_le(0xff, mc_hash->byte);
+
+ falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER);
+ falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER);
+}
+
+/**************************************************************************
+ *
+ * Device reset
+ *
+ **************************************************************************
+ */
+
+/* Resets NIC to known state. This routine must be called in process
+ * context and is allowed to sleep. */
+int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t glb_ctl_reg_ker;
+ int rc;
+
+ EFX_LOG(efx, "performing hardware reset (%d)\n", method);
+
+ /* Initiate device reset */
+ if (method == RESET_TYPE_WORLD) {
+ rc = pci_save_state(efx->pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to backup PCI state of primary "
+ "function prior to hardware reset\n");
+ goto fail1;
+ }
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ rc = pci_save_state(nic_data->pci_dev2);
+ if (rc) {
+ EFX_ERR(efx, "failed to backup PCI state of "
+ "secondary function prior to "
+ "hardware reset\n");
+ goto fail2;
+ }
+ }
+
+ EFX_POPULATE_OWORD_2(glb_ctl_reg_ker,
+ EXT_PHY_RST_DUR, 0x7,
+ SWRST, 1);
+ } else {
+ int reset_phy = (method == RESET_TYPE_INVISIBLE ?
+ EXCLUDE_FROM_RESET : 0);
+
+ EFX_POPULATE_OWORD_7(glb_ctl_reg_ker,
+ EXT_PHY_RST_CTL, reset_phy,
+ PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+ PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+ PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+ EE_RST_CTL, EXCLUDE_FROM_RESET,
+ EXT_PHY_RST_DUR, 0x7 /* 10ms */,
+ SWRST, 1);
+ }
+ falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+
+ EFX_LOG(efx, "waiting for hardware reset\n");
+ schedule_timeout_uninterruptible(HZ / 20);
+
+ /* Restore PCI configuration if needed */
+ if (method == RESET_TYPE_WORLD) {
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ rc = pci_restore_state(nic_data->pci_dev2);
+ if (rc) {
+ EFX_ERR(efx, "failed to restore PCI config for "
+ "the secondary function\n");
+ goto fail3;
+ }
+ }
+ rc = pci_restore_state(efx->pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to restore PCI config for the "
+ "primary function\n");
+ goto fail4;
+ }
+ EFX_LOG(efx, "successfully restored PCI config\n");
+ }
+
+ /* Assert that reset complete */
+ falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+ if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) {
+ rc = -ETIMEDOUT;
+ EFX_ERR(efx, "timed out waiting for hardware reset\n");
+ goto fail5;
+ }
+ EFX_LOG(efx, "hardware reset complete\n");
+
+ return 0;
+
+ /* pci_save_state() and pci_restore_state() MUST be called in pairs */
+fail2:
+fail3:
+ pci_restore_state(efx->pci_dev);
+fail1:
+fail4:
+fail5:
+ return rc;
+}
+
+/* Zeroes out the SRAM contents. This routine must be called in
+ * process context and is allowed to sleep.
+ */
+static int falcon_reset_sram(struct efx_nic *efx)
+{
+ efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker;
+ int count;
+
+ /* Set the SRAM wake/sleep GPIO appropriately. */
+ falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1);
+ falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+
+ /* Initiate SRAM reset */
+ EFX_POPULATE_OWORD_2(srm_cfg_reg_ker,
+ SRAM_OOB_BT_INIT_EN, 1,
+ SRM_NUM_BANKS_AND_BANK_SIZE, 0);
+ falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+
+ /* Wait for SRAM reset to complete */
+ count = 0;
+ do {
+ EFX_LOG(efx, "waiting for SRAM reset (attempt %d)...\n", count);
+
+ /* SRAM reset is slow; expect around 16ms */
+ schedule_timeout_uninterruptible(HZ / 50);
+
+ /* Check for reset complete */
+ falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+ if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) {
+ EFX_LOG(efx, "SRAM reset complete\n");
+
+ return 0;
+ }
+ } while (++count < 20); /* wait upto 0.4 sec */
+
+ EFX_ERR(efx, "timed out waiting for SRAM reset\n");
+ return -ETIMEDOUT;
+}
+
+/* Extract non-volatile configuration */
+static int falcon_probe_nvconfig(struct efx_nic *efx)
+{
+ struct falcon_nvconfig *nvconfig;
+ efx_oword_t nic_stat;
+ int device_id;
+ unsigned addr_len;
+ size_t offset, len;
+ int magic_num, struct_ver, board_rev;
+ int rc;
+
+ /* Find the boot device. */
+ falcon_read(efx, &nic_stat, NIC_STAT_REG);
+ if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) {
+ device_id = EE_SPI_FLASH;
+ addr_len = 3;
+ } else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) {
+ device_id = EE_SPI_EEPROM;
+ addr_len = 2;
+ } else {
+ return -ENODEV;
+ }
+
+ nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
+
+ /* Read the whole configuration structure into memory. */
+ for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
+ len = min(sizeof(*nvconfig) - offset,
+ (size_t) FALCON_SPI_MAX_LEN);
+ rc = falcon_spi_read(efx, device_id, SPI_READ,
+ NVCONFIG_BASE + offset, addr_len,
+ (char *)nvconfig + offset, len);
+ if (rc)
+ goto out;
+ }
+
+ /* Read the MAC addresses */
+ memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
+
+ /* Read the board configuration. */
+ magic_num = le16_to_cpu(nvconfig->board_magic_num);
+ struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
+
+ if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) {
+ EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x "
+ "therefore using defaults\n", magic_num, struct_ver);
+ efx->phy_type = PHY_TYPE_NONE;
+ efx->mii.phy_id = PHY_ADDR_INVALID;
+ board_rev = 0;
+ } else {
+ struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
+
+ efx->phy_type = v2->port0_phy_type;
+ efx->mii.phy_id = v2->port0_phy_addr;
+ board_rev = le16_to_cpu(v2->board_revision);
+ }
+
+ EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
+
+ efx_set_board_info(efx, board_rev);
+
+ out:
+ kfree(nvconfig);
+ return rc;
+}
+
+/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
+ * count, port speed). Set workaround and feature flags accordingly.
+ */
+static int falcon_probe_nic_variant(struct efx_nic *efx)
+{
+ efx_oword_t altera_build;
+
+ falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
+ if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
+ EFX_ERR(efx, "Falcon FPGA not supported\n");
+ return -ENODEV;
+ }
+
+ switch (FALCON_REV(efx)) {
+ case FALCON_REV_A0:
+ case 0xff:
+ EFX_ERR(efx, "Falcon rev A0 not supported\n");
+ return -ENODEV;
+
+ case FALCON_REV_A1:{
+ efx_oword_t nic_stat;
+
+ falcon_read(efx, &nic_stat, NIC_STAT_REG);
+
+ if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
+ EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+ return -ENODEV;
+ }
+ if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) {
+ EFX_ERR(efx, "1G mode not supported\n");
+ return -ENODEV;
+ }
+ break;
+ }
+
+ case FALCON_REV_B0:
+ break;
+
+ default:
+ EFX_ERR(efx, "Unknown Falcon rev %d\n", FALCON_REV(efx));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int falcon_probe_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data;
+ int rc;
+
+ /* Initialise I2C interface state */
+ efx->i2c.efx = efx;
+ efx->i2c.op = &falcon_i2c_bit_operations;
+ efx->i2c.sda = 1;
+ efx->i2c.scl = 1;
+
+ /* Allocate storage for hardware specific data */
+ nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
+ efx->nic_data = (void *) nic_data;
+
+ /* Determine number of ports etc. */
+ rc = falcon_probe_nic_variant(efx);
+ if (rc)
+ goto fail1;
+
+ /* Probe secondary function if expected */
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ struct pci_dev *dev = pci_dev_get(efx->pci_dev);
+
+ while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
+ dev))) {
+ if (dev->bus == efx->pci_dev->bus &&
+ dev->devfn == efx->pci_dev->devfn + 1) {
+ nic_data->pci_dev2 = dev;
+ break;
+ }
+ }
+ if (!nic_data->pci_dev2) {
+ EFX_ERR(efx, "failed to find secondary function\n");
+ rc = -ENODEV;
+ goto fail2;
+ }
+ }
+
+ /* Now we can reset the NIC */
+ rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
+ if (rc) {
+ EFX_ERR(efx, "failed to reset NIC\n");
+ goto fail3;
+ }
+
+ /* Allocate memory for INT_KER */
+ rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
+ if (rc)
+ goto fail4;
+ BUG_ON(efx->irq_status.dma_addr & 0x0f);
+
+ EFX_LOG(efx, "INT_KER at %llx (virt %p phys %lx)\n",
+ (unsigned long long)efx->irq_status.dma_addr,
+ efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
+
+ /* Read in the non-volatile configuration */
+ rc = falcon_probe_nvconfig(efx);
+ if (rc)
+ goto fail5;
+
+ return 0;
+
+ fail5:
+ falcon_free_buffer(efx, &efx->irq_status);
+ fail4:
+ fail3:
+ if (nic_data->pci_dev2) {
+ pci_dev_put(nic_data->pci_dev2);
+ nic_data->pci_dev2 = NULL;
+ }
+ fail2:
+ fail1:
+ kfree(efx->nic_data);
+ return rc;
+}
+
+/* This call performs hardware-specific global initialisation, such as
+ * defining the descriptor cache sizes and number of RSS channels.
+ * It does not set up any buffers, descriptor rings or event queues.
+ */
+int falcon_init_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *data;
+ efx_oword_t temp;
+ unsigned thresh;
+ int rc;
+
+ data = (struct falcon_nic_data *)efx->nic_data;
+
+ /* Set up the address region register. This is only needed
+ * for the B0 FPGA, but since we are just pushing in the
+ * reset defaults this may as well be unconditional. */
+ EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0,
+ ADR_REGION1, (1 << 16),
+ ADR_REGION2, (2 << 16),
+ ADR_REGION3, (3 << 16));
+ falcon_write(efx, &temp, ADR_REGION_REG_KER);
+
+ /* Use on-chip SRAM */
+ falcon_read(efx, &temp, NIC_STAT_REG);
+ EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
+ falcon_write(efx, &temp, NIC_STAT_REG);
+
+ /* Set buffer table mode */
+ EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
+ falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
+
+ rc = falcon_reset_sram(efx);
+ if (rc)
+ return rc;
+
+ /* Set positions of descriptor caches in SRAM. */
+ EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
+ falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
+ falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER);
+
+ /* Set TX descriptor cache size. */
+ BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER));
+ EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, TX_DC_ENTRIES_ORDER);
+ falcon_write(efx, &temp, TX_DC_CFG_REG_KER);
+
+ /* Set RX descriptor cache size. Set low watermark to size-8, as
+ * this allows most efficient prefetching.
+ */
+ BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER));
+ EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, RX_DC_ENTRIES_ORDER);
+ falcon_write(efx, &temp, RX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
+ falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER);
+
+ /* Clear the parity enables on the TX data fifos as
+ * they produce false parity errors because of timing issues
+ */
+ if (EFX_WORKAROUND_5129(efx)) {
+ falcon_read(efx, &temp, SPARE_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0);
+ falcon_write(efx, &temp, SPARE_REG_KER);
+ }
+
+ /* Enable all the genuinely fatal interrupts. (They are still
+ * masked by the overall interrupt mask, controlled by
+ * falcon_interrupts()).
+ *
+ * Note: All other fatal interrupts are enabled
+ */
+ EFX_POPULATE_OWORD_3(temp,
+ ILL_ADR_INT_KER_EN, 1,
+ RBUF_OWN_INT_KER_EN, 1,
+ TBUF_OWN_INT_KER_EN, 1);
+ EFX_INVERT_OWORD(temp);
+ falcon_write(efx, &temp, FATAL_INTR_REG_KER);
+
+ /* Set number of RSS queues for receive path. */
+ falcon_read(efx, &temp, RX_FILTER_CTL_REG);
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
+ else
+ EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
+ if (EFX_WORKAROUND_7244(efx)) {
+ EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
+ }
+ falcon_write(efx, &temp, RX_FILTER_CTL_REG);
+
+ falcon_setup_rss_indir_table(efx);
+
+ /* Setup RX. Wait for descriptor is broken and must
+ * be disabled. RXDP recovery shouldn't be needed, but is.
+ */
+ falcon_read(efx, &temp, RX_SELF_RST_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1);
+ EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1);
+ if (EFX_WORKAROUND_5583(efx))
+ EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1);
+ falcon_write(efx, &temp, RX_SELF_RST_REG_KER);
+
+ /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
+ * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
+ */
+ falcon_read(efx, &temp, TX_CFG2_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe);
+ EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1);
+ EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1);
+ EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1);
+ /* Enable SW_EV to inherit in char driver - assume harmless here */
+ EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1);
+ /* Prefetch threshold 2 => fetch when descriptor cache half empty */
+ EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
+ /* Squash TX of packets of 16 bytes or less */
+ if (FALCON_REV(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
+ EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
+ falcon_write(efx, &temp, TX_CFG2_REG_KER);
+
+ /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
+ * descriptors (which is bad).
+ */
+ falcon_read(efx, &temp, TX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0);
+ falcon_write(efx, &temp, TX_CFG_REG_KER);
+
+ /* RX config */
+ falcon_read(efx, &temp, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0);
+ if (EFX_WORKAROUND_7575(efx))
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
+ (3 * 4096) / 32);
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
+
+ /* RX FIFO flow control thresholds */
+ thresh = ((rx_xon_thresh_bytes >= 0) ?
+ rx_xon_thresh_bytes : efx->type->rx_xon_thresh);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256);
+ thresh = ((rx_xoff_thresh_bytes >= 0) ?
+ rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
+ /* RX control FIFO thresholds [32 entries] */
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
+ falcon_write(efx, &temp, RX_CFG_REG_KER);
+
+ /* Set destination of both TX and RX Flush events */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
+ falcon_write(efx, &temp, DP_CTRL_REG);
+ }
+
+ return 0;
+}
+
+void falcon_remove_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ falcon_free_buffer(efx, &efx->irq_status);
+
+ (void) falcon_reset_hw(efx, RESET_TYPE_ALL);
+
+ /* Release the second function after the reset */
+ if (nic_data->pci_dev2) {
+ pci_dev_put(nic_data->pci_dev2);
+ nic_data->pci_dev2 = NULL;
+ }
+
+ /* Tear down the private nic state */
+ kfree(efx->nic_data);
+ efx->nic_data = NULL;
+}
+
+void falcon_update_nic_stats(struct efx_nic *efx)
+{
+ efx_oword_t cnt;
+
+ falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER);
+ efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT);
+}
+
+/**************************************************************************
+ *
+ * Revision-dependent attributes used by efx.c
+ *
+ **************************************************************************
+ */
+
+struct efx_nic_type falcon_a_nic_type = {
+ .mem_bar = 2,
+ .mem_map_size = 0x20000,
+ .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1,
+ .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1,
+ .buf_tbl_base = BUF_TBL_KER_A1,
+ .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1,
+ .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1,
+ .txd_ring_mask = FALCON_TXD_RING_MASK,
+ .rxd_ring_mask = FALCON_RXD_RING_MASK,
+ .evq_size = FALCON_EVQ_SIZE,
+ .max_dma_mask = FALCON_DMA_MASK,
+ .tx_dma_mask = FALCON_TX_DMA_MASK,
+ .bug5391_mask = 0xf,
+ .rx_xoff_thresh = 2048,
+ .rx_xon_thresh = 512,
+ .rx_buffer_padding = 0x24,
+ .max_interrupt_mode = EFX_INT_MODE_MSI,
+ .phys_addr_channels = 4,
+};
+
+struct efx_nic_type falcon_b_nic_type = {
+ .mem_bar = 2,
+ /* Map everything up to and including the RSS indirection
+ * table. Don't map MSI-X table, MSI-X PBA since Linux
+ * requires that they not be mapped. */
+ .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800,
+ .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0,
+ .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0,
+ .buf_tbl_base = BUF_TBL_KER_B0,
+ .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0,
+ .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0,
+ .txd_ring_mask = FALCON_TXD_RING_MASK,
+ .rxd_ring_mask = FALCON_RXD_RING_MASK,
+ .evq_size = FALCON_EVQ_SIZE,
+ .max_dma_mask = FALCON_DMA_MASK,
+ .tx_dma_mask = FALCON_TX_DMA_MASK,
+ .bug5391_mask = 0,
+ .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */
+ .rx_xon_thresh = 27648, /* ~3*max MTU */
+ .rx_buffer_padding = 0,
+ .max_interrupt_mode = EFX_INT_MODE_MSIX,
+ .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
+ * interrupt handler only supports 32
+ * channels */
+};
+
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
new file mode 100644
index 000000000000..6117403b0c03
--- /dev/null
+++ b/drivers/net/sfc/falcon.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_H
+#define EFX_FALCON_H
+
+#include "net_driver.h"
+
+/*
+ * Falcon hardware control
+ */
+
+enum falcon_revision {
+ FALCON_REV_A0 = 0,
+ FALCON_REV_A1 = 1,
+ FALCON_REV_B0 = 2,
+};
+
+#define FALCON_REV(efx) ((efx)->pci_dev->revision)
+
+extern struct efx_nic_type falcon_a_nic_type;
+extern struct efx_nic_type falcon_b_nic_type;
+
+/**************************************************************************
+ *
+ * Externs
+ *
+ **************************************************************************
+ */
+
+/* TX data path */
+extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
+extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
+
+/* RX data path */
+extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
+extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
+
+/* Event data path */
+extern int falcon_probe_eventq(struct efx_channel *channel);
+extern int falcon_init_eventq(struct efx_channel *channel);
+extern void falcon_fini_eventq(struct efx_channel *channel);
+extern void falcon_remove_eventq(struct efx_channel *channel);
+extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota);
+extern void falcon_eventq_read_ack(struct efx_channel *channel);
+
+/* Ports */
+extern int falcon_probe_port(struct efx_nic *efx);
+extern void falcon_remove_port(struct efx_nic *efx);
+
+/* MAC/PHY */
+extern int falcon_xaui_link_ok(struct efx_nic *efx);
+extern int falcon_dma_stats(struct efx_nic *efx,
+ unsigned int done_offset);
+extern void falcon_drain_tx_fifo(struct efx_nic *efx);
+extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
+
+/* Interrupts and test events */
+extern int falcon_init_interrupt(struct efx_nic *efx);
+extern void falcon_enable_interrupts(struct efx_nic *efx);
+extern void falcon_generate_test_event(struct efx_channel *channel,
+ unsigned int magic);
+extern void falcon_generate_interrupt(struct efx_nic *efx);
+extern void falcon_set_int_moderation(struct efx_channel *channel);
+extern void falcon_disable_interrupts(struct efx_nic *efx);
+extern void falcon_fini_interrupt(struct efx_nic *efx);
+
+/* Global Resources */
+extern int falcon_probe_nic(struct efx_nic *efx);
+extern int falcon_probe_resources(struct efx_nic *efx);
+extern int falcon_init_nic(struct efx_nic *efx);
+extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
+extern void falcon_remove_resources(struct efx_nic *efx);
+extern void falcon_remove_nic(struct efx_nic *efx);
+extern void falcon_update_nic_stats(struct efx_nic *efx);
+extern void falcon_set_multicast_hash(struct efx_nic *efx);
+extern int falcon_reset_xaui(struct efx_nic *efx);
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ */
+
+#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
+#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
+
+/* Retrieve statistic from statistics block */
+#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \
+ if (FALCON_STAT_WIDTH(falcon_stat) == 16) \
+ (efx)->mac_stats.efx_stat += le16_to_cpu( \
+ *((__force __le16 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \
+ (efx)->mac_stats.efx_stat += le32_to_cpu( \
+ *((__force __le32 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ else \
+ (efx)->mac_stats.efx_stat += le64_to_cpu( \
+ *((__force __le64 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ } while (0)
+
+#define FALCON_MAC_STATS_SIZE 0x100
+
+#define MAC_DATA_LBN 0
+#define MAC_DATA_WIDTH 32
+
+extern void falcon_generate_event(struct efx_channel *channel,
+ efx_qword_t *event);
+
+#endif /* EFX_FALCON_H */
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
new file mode 100644
index 000000000000..06e2d68fc3d1
--- /dev/null
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -0,0 +1,1149 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_HWDEFS_H
+#define EFX_FALCON_HWDEFS_H
+
+/*
+ * Falcon hardware value definitions.
+ * Falcon is the internal codename for the SFC4000 controller that is
+ * present in SFE400X evaluation boards
+ */
+
+/**************************************************************************
+ *
+ * Falcon registers
+ *
+ **************************************************************************
+ */
+
+/* Address region register */
+#define ADR_REGION_REG_KER 0x00
+#define ADR_REGION0_LBN 0
+#define ADR_REGION0_WIDTH 18
+#define ADR_REGION1_LBN 32
+#define ADR_REGION1_WIDTH 18
+#define ADR_REGION2_LBN 64
+#define ADR_REGION2_WIDTH 18
+#define ADR_REGION3_LBN 96
+#define ADR_REGION3_WIDTH 18
+
+/* Interrupt enable register */
+#define INT_EN_REG_KER 0x0010
+#define KER_INT_KER_LBN 3
+#define KER_INT_KER_WIDTH 1
+#define DRV_INT_EN_KER_LBN 0
+#define DRV_INT_EN_KER_WIDTH 1
+
+/* Interrupt status address register */
+#define INT_ADR_REG_KER 0x0030
+#define NORM_INT_VEC_DIS_KER_LBN 64
+#define NORM_INT_VEC_DIS_KER_WIDTH 1
+#define INT_ADR_KER_LBN 0
+#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */
+
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define INT_ACK_REG_KER_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* SPI host command register */
+#define EE_SPI_HCMD_REG_KER 0x0100
+#define EE_SPI_HCMD_CMD_EN_LBN 31
+#define EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define EE_WR_TIMER_ACTIVE_LBN 28
+#define EE_WR_TIMER_ACTIVE_WIDTH 1
+#define EE_SPI_HCMD_SF_SEL_LBN 24
+#define EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define EE_SPI_EEPROM 0
+#define EE_SPI_FLASH 1
+#define EE_SPI_HCMD_DABCNT_LBN 16
+#define EE_SPI_HCMD_DABCNT_WIDTH 5
+#define EE_SPI_HCMD_READ_LBN 15
+#define EE_SPI_HCMD_READ_WIDTH 1
+#define EE_SPI_READ 1
+#define EE_SPI_WRITE 0
+#define EE_SPI_HCMD_DUBCNT_LBN 12
+#define EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define EE_SPI_HCMD_ADBCNT_LBN 8
+#define EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define EE_SPI_HCMD_ENC_LBN 0
+#define EE_SPI_HCMD_ENC_WIDTH 8
+
+/* SPI host address register */
+#define EE_SPI_HADR_REG_KER 0x0110
+#define EE_SPI_HADR_ADR_LBN 0
+#define EE_SPI_HADR_ADR_WIDTH 24
+
+/* SPI host data register */
+#define EE_SPI_HDATA_REG_KER 0x0120
+
+/* PCIE CORE ACCESS REG */
+#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
+#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
+#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700
+#define PCIE_CORE_ADDR_ACK_FREQ 0x70C
+
+/* NIC status register */
+#define NIC_STAT_REG 0x0200
+#define ONCHIP_SRAM_LBN 16
+#define ONCHIP_SRAM_WIDTH 1
+#define SF_PRST_LBN 9
+#define SF_PRST_WIDTH 1
+#define EE_PRST_LBN 8
+#define EE_PRST_WIDTH 1
+/* See pic_mode_t for decoding of this field */
+/* These bit definitions are extrapolated from the list of numerical
+ * values for STRAP_PINS.
+ */
+#define STRAP_10G_LBN 2
+#define STRAP_10G_WIDTH 1
+#define STRAP_PCIE_LBN 0
+#define STRAP_PCIE_WIDTH 1
+
+/* GPIO control register */
+#define GPIO_CTL_REG_KER 0x0210
+#define GPIO_OUTPUTS_LBN (16)
+#define GPIO_OUTPUTS_WIDTH (4)
+#define GPIO_INPUTS_LBN (8)
+#define GPIO_DIRECTION_LBN (24)
+#define GPIO_DIRECTION_WIDTH (4)
+#define GPIO_DIRECTION_OUT (1)
+#define GPIO_SRAM_SLEEP (1 << 1)
+
+#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3)
+#define GPIO3_OEN_WIDTH 1
+#define GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2)
+#define GPIO2_OEN_WIDTH 1
+#define GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1)
+#define GPIO1_OEN_WIDTH 1
+#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0)
+#define GPIO0_OEN_WIDTH 1
+
+#define GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3)
+#define GPIO3_OUT_WIDTH 1
+#define GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2)
+#define GPIO2_OUT_WIDTH 1
+#define GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1)
+#define GPIO1_OUT_WIDTH 1
+#define GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0)
+#define GPIO0_OUT_WIDTH 1
+
+#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3)
+#define GPIO3_IN_WIDTH 1
+#define GPIO2_IN_WIDTH 1
+#define GPIO1_IN_WIDTH 1
+#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0)
+#define GPIO0_IN_WIDTH 1
+
+/* Global control register */
+#define GLB_CTL_REG_KER 0x0220
+#define EXT_PHY_RST_CTL_LBN 63
+#define EXT_PHY_RST_CTL_WIDTH 1
+#define PCIE_SD_RST_CTL_LBN 61
+#define PCIE_SD_RST_CTL_WIDTH 1
+
+#define PCIE_NSTCK_RST_CTL_LBN 58
+#define PCIE_NSTCK_RST_CTL_WIDTH 1
+#define PCIE_CORE_RST_CTL_LBN 57
+#define PCIE_CORE_RST_CTL_WIDTH 1
+#define EE_RST_CTL_LBN 49
+#define EE_RST_CTL_WIDTH 1
+#define RST_XGRX_LBN 24
+#define RST_XGRX_WIDTH 1
+#define RST_XGTX_LBN 23
+#define RST_XGTX_WIDTH 1
+#define RST_EM_LBN 22
+#define RST_EM_WIDTH 1
+#define EXT_PHY_RST_DUR_LBN 1
+#define EXT_PHY_RST_DUR_WIDTH 3
+#define SWRST_LBN 0
+#define SWRST_WIDTH 1
+#define INCLUDE_IN_RESET 0
+#define EXCLUDE_FROM_RESET 1
+
+/* Fatal interrupt register */
+#define FATAL_INTR_REG_KER 0x0230
+#define RBUF_OWN_INT_KER_EN_LBN 39
+#define RBUF_OWN_INT_KER_EN_WIDTH 1
+#define TBUF_OWN_INT_KER_EN_LBN 38
+#define TBUF_OWN_INT_KER_EN_WIDTH 1
+#define ILL_ADR_INT_KER_EN_LBN 33
+#define ILL_ADR_INT_KER_EN_WIDTH 1
+#define MEM_PERR_INT_KER_LBN 8
+#define MEM_PERR_INT_KER_WIDTH 1
+#define INT_KER_ERROR_LBN 0
+#define INT_KER_ERROR_WIDTH 12
+
+#define DP_CTRL_REG 0x250
+#define FLS_EVQ_ID_LBN 0
+#define FLS_EVQ_ID_WIDTH 11
+
+#define MEM_STAT_REG_KER 0x260
+
+/* Debug probe register */
+#define DEBUG_BLK_SEL_MISC 7
+#define DEBUG_BLK_SEL_SERDES 6
+#define DEBUG_BLK_SEL_EM 5
+#define DEBUG_BLK_SEL_SR 4
+#define DEBUG_BLK_SEL_EV 3
+#define DEBUG_BLK_SEL_RX 2
+#define DEBUG_BLK_SEL_TX 1
+#define DEBUG_BLK_SEL_BIU 0
+
+/* FPGA build version */
+#define ALTERA_BUILD_REG_KER 0x0300
+#define VER_ALL_LBN 0
+#define VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define SPARE_REG_KER 0x310
+#define MEM_PERR_EN_TX_DATA_LBN 72
+#define MEM_PERR_EN_TX_DATA_WIDTH 2
+
+/* Timer table for kernel access */
+#define TIMER_CMD_REG_KER 0x420
+#define TIMER_MODE_LBN 12
+#define TIMER_MODE_WIDTH 2
+#define TIMER_MODE_DIS 0
+#define TIMER_MODE_INT_HLDOFF 2
+#define TIMER_VAL_LBN 0
+#define TIMER_VAL_WIDTH 12
+
+/* Driver generated event register */
+#define DRV_EV_REG_KER 0x440
+#define DRV_EV_QID_LBN 64
+#define DRV_EV_QID_WIDTH 12
+#define DRV_EV_DATA_LBN 0
+#define DRV_EV_DATA_WIDTH 64
+
+/* Buffer table configuration register */
+#define BUF_TBL_CFG_REG_KER 0x600
+#define BUF_TBL_MODE_LBN 3
+#define BUF_TBL_MODE_WIDTH 1
+#define BUF_TBL_MODE_HALF 0
+#define BUF_TBL_MODE_FULL 1
+
+/* SRAM receive descriptor cache configuration register */
+#define SRM_RX_DC_CFG_REG_KER 0x610
+#define SRM_RX_DC_BASE_ADR_LBN 0
+#define SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM transmit descriptor cache configuration register */
+#define SRM_TX_DC_CFG_REG_KER 0x620
+#define SRM_TX_DC_BASE_ADR_LBN 0
+#define SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM configuration register */
+#define SRM_CFG_REG_KER 0x630
+#define SRAM_OOB_BT_INIT_EN_LBN 3
+#define SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+#define SRM_NB_BSZ_1BANKS_2M 0
+#define SRM_NB_BSZ_1BANKS_4M 1
+#define SRM_NB_BSZ_1BANKS_8M 2
+#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */
+#define SRM_NB_BSZ_2BANKS_4M 4
+#define SRM_NB_BSZ_2BANKS_8M 5
+#define SRM_NB_BSZ_2BANKS_16M 6
+#define SRM_NB_BSZ_RESERVED 7
+
+/* Special buffer table update register */
+#define BUF_TBL_UPD_REG_KER 0x0650
+#define BUF_UPD_CMD_LBN 63
+#define BUF_UPD_CMD_WIDTH 1
+#define BUF_CLR_CMD_LBN 62
+#define BUF_CLR_CMD_WIDTH 1
+#define BUF_CLR_END_ID_LBN 32
+#define BUF_CLR_END_ID_WIDTH 20
+#define BUF_CLR_START_ID_LBN 0
+#define BUF_CLR_START_ID_WIDTH 20
+
+/* Receive configuration register */
+#define RX_CFG_REG_KER 0x800
+
+/* B0 */
+#define RX_INGR_EN_B0_LBN 47
+#define RX_INGR_EN_B0_WIDTH 1
+#define RX_DESC_PUSH_EN_B0_LBN 43
+#define RX_DESC_PUSH_EN_B0_WIDTH 1
+#define RX_XON_TX_TH_B0_LBN 33
+#define RX_XON_TX_TH_B0_WIDTH 5
+#define RX_XOFF_TX_TH_B0_LBN 28
+#define RX_XOFF_TX_TH_B0_WIDTH 5
+#define RX_USR_BUF_SIZE_B0_LBN 19
+#define RX_USR_BUF_SIZE_B0_WIDTH 9
+#define RX_XON_MAC_TH_B0_LBN 10
+#define RX_XON_MAC_TH_B0_WIDTH 9
+#define RX_XOFF_MAC_TH_B0_LBN 1
+#define RX_XOFF_MAC_TH_B0_WIDTH 9
+#define RX_XOFF_MAC_EN_B0_LBN 0
+#define RX_XOFF_MAC_EN_B0_WIDTH 1
+
+/* A1 */
+#define RX_DESC_PUSH_EN_A1_LBN 35
+#define RX_DESC_PUSH_EN_A1_WIDTH 1
+#define RX_XON_TX_TH_A1_LBN 25
+#define RX_XON_TX_TH_A1_WIDTH 5
+#define RX_XOFF_TX_TH_A1_LBN 20
+#define RX_XOFF_TX_TH_A1_WIDTH 5
+#define RX_USR_BUF_SIZE_A1_LBN 11
+#define RX_USR_BUF_SIZE_A1_WIDTH 9
+#define RX_XON_MAC_TH_A1_LBN 6
+#define RX_XON_MAC_TH_A1_WIDTH 5
+#define RX_XOFF_MAC_TH_A1_LBN 1
+#define RX_XOFF_MAC_TH_A1_WIDTH 5
+#define RX_XOFF_MAC_EN_A1_LBN 0
+#define RX_XOFF_MAC_EN_A1_WIDTH 1
+
+/* Receive filter control register */
+#define RX_FILTER_CTL_REG 0x810
+#define UDP_FULL_SRCH_LIMIT_LBN 32
+#define UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define NUM_KER_LBN 24
+#define NUM_KER_WIDTH 2
+#define UDP_WILD_SRCH_LIMIT_LBN 16
+#define UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define TCP_WILD_SRCH_LIMIT_LBN 8
+#define TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define TCP_FULL_SRCH_LIMIT_LBN 0
+#define TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define RX_FLUSH_DESCQ_REG_KER 0x0820
+#define RX_FLUSH_DESCQ_CMD_LBN 24
+#define RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define RX_FLUSH_DESCQ_LBN 0
+#define RX_FLUSH_DESCQ_WIDTH 12
+
+/* Receive descriptor update register */
+#define RX_DESC_UPD_REG_KER_DWORD (0x830 + 12)
+#define RX_DESC_WPTR_DWORD_LBN 0
+#define RX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Receive descriptor cache configuration register */
+#define RX_DC_CFG_REG_KER 0x840
+#define RX_DC_SIZE_LBN 0
+#define RX_DC_SIZE_WIDTH 2
+
+#define RX_DC_PF_WM_REG_KER 0x850
+#define RX_DC_PF_LWM_LBN 0
+#define RX_DC_PF_LWM_WIDTH 6
+
+/* RX no descriptor drop counter */
+#define RX_NODESC_DROP_REG_KER 0x880
+#define RX_NODESC_DROP_CNT_LBN 0
+#define RX_NODESC_DROP_CNT_WIDTH 16
+
+/* RX black magic register */
+#define RX_SELF_RST_REG_KER 0x890
+#define RX_ISCSI_DIS_LBN 17
+#define RX_ISCSI_DIS_WIDTH 1
+#define RX_NODESC_WAIT_DIS_LBN 9
+#define RX_NODESC_WAIT_DIS_WIDTH 1
+#define RX_RECOVERY_EN_LBN 8
+#define RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define TX_FLUSH_DESCQ_CMD_LBN 12
+#define TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define TX_FLUSH_DESCQ_LBN 0
+#define TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit descriptor update register */
+#define TX_DESC_UPD_REG_KER_DWORD (0xa10 + 12)
+#define TX_DESC_WPTR_DWORD_LBN 0
+#define TX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Transmit descriptor cache configuration register */
+#define TX_DC_CFG_REG_KER 0xa20
+#define TX_DC_SIZE_LBN 0
+#define TX_DC_SIZE_WIDTH 2
+
+/* Transmit checksum configuration register (A0/A1 only) */
+#define TX_CHKSM_CFG_REG_KER_A1 0xa30
+
+/* Transmit configuration register */
+#define TX_CFG_REG_KER 0xa50
+#define TX_NO_EOP_DISC_EN_LBN 5
+#define TX_NO_EOP_DISC_EN_WIDTH 1
+
+/* Transmit configuration register 2 */
+#define TX_CFG2_REG_KER 0xa80
+#define TX_CSR_PUSH_EN_LBN 89
+#define TX_CSR_PUSH_EN_WIDTH 1
+#define TX_RX_SPACER_LBN 64
+#define TX_RX_SPACER_WIDTH 8
+#define TX_SW_EV_EN_LBN 59
+#define TX_SW_EV_EN_WIDTH 1
+#define TX_RX_SPACER_EN_LBN 57
+#define TX_RX_SPACER_EN_WIDTH 1
+#define TX_PREF_THRESHOLD_LBN 19
+#define TX_PREF_THRESHOLD_WIDTH 2
+#define TX_ONE_PKT_PER_Q_LBN 18
+#define TX_ONE_PKT_PER_Q_WIDTH 1
+#define TX_DIS_NON_IP_EV_LBN 17
+#define TX_DIS_NON_IP_EV_WIDTH 1
+#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
+#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
+
+/* PHY management transmit data register */
+#define MD_TXD_REG_KER 0xc00
+#define MD_TXD_LBN 0
+#define MD_TXD_WIDTH 16
+
+/* PHY management receive data register */
+#define MD_RXD_REG_KER 0xc10
+#define MD_RXD_LBN 0
+#define MD_RXD_WIDTH 16
+
+/* PHY management configuration & status register */
+#define MD_CS_REG_KER 0xc20
+#define MD_GC_LBN 4
+#define MD_GC_WIDTH 1
+#define MD_RIC_LBN 2
+#define MD_RIC_WIDTH 1
+#define MD_RDC_LBN 1
+#define MD_RDC_WIDTH 1
+#define MD_WRC_LBN 0
+#define MD_WRC_WIDTH 1
+
+/* PHY management PHY address register */
+#define MD_PHY_ADR_REG_KER 0xc30
+#define MD_PHY_ADR_LBN 0
+#define MD_PHY_ADR_WIDTH 16
+
+/* PHY management ID register */
+#define MD_ID_REG_KER 0xc40
+#define MD_PRT_ADR_LBN 11
+#define MD_PRT_ADR_WIDTH 5
+#define MD_DEV_ADR_LBN 6
+#define MD_DEV_ADR_WIDTH 5
+/* Used for writing both at once */
+#define MD_PRT_DEV_ADR_LBN 6
+#define MD_PRT_DEV_ADR_WIDTH 10
+
+/* PHY management status & mask register (DWORD read only) */
+#define MD_STAT_REG_KER 0xc50
+#define MD_BSERR_LBN 2
+#define MD_BSERR_WIDTH 1
+#define MD_LNFL_LBN 1
+#define MD_LNFL_WIDTH 1
+#define MD_BSY_LBN 0
+#define MD_BSY_WIDTH 1
+
+/* Port 0 and 1 MAC stats registers */
+#define MAC0_STAT_DMA_REG_KER 0xc60
+#define MAC_STAT_DMA_CMD_LBN 48
+#define MAC_STAT_DMA_CMD_WIDTH 1
+#define MAC_STAT_DMA_ADR_LBN 0
+#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/* Port 0 and 1 MAC control registers */
+#define MAC0_CTRL_REG_KER 0xc80
+#define MAC_XOFF_VAL_LBN 16
+#define MAC_XOFF_VAL_WIDTH 16
+#define TXFIFO_DRAIN_EN_B0_LBN 7
+#define TXFIFO_DRAIN_EN_B0_WIDTH 1
+#define MAC_BCAD_ACPT_LBN 4
+#define MAC_BCAD_ACPT_WIDTH 1
+#define MAC_UC_PROM_LBN 3
+#define MAC_UC_PROM_WIDTH 1
+#define MAC_LINK_STATUS_LBN 2
+#define MAC_LINK_STATUS_WIDTH 1
+#define MAC_SPEED_LBN 0
+#define MAC_SPEED_WIDTH 2
+
+/* 10G XAUI XGXS default values */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
+
+/* Multicast address hash table */
+#define MAC_MCAST_HASH_REG0_KER 0xca0
+#define MAC_MCAST_HASH_REG1_KER 0xcb0
+
+/* GMAC registers */
+#define FALCON_GMAC_REGBANK 0xe00
+#define FALCON_GMAC_REGBANK_SIZE 0x200
+#define FALCON_GMAC_REG_SIZE 0x10
+
+/* XMAC registers */
+#define FALCON_XMAC_REGBANK 0x1200
+#define FALCON_XMAC_REGBANK_SIZE 0x200
+#define FALCON_XMAC_REG_SIZE 0x10
+
+/* XGMAC address register low */
+#define XM_ADR_LO_REG_MAC 0x00
+#define XM_ADR_3_LBN 24
+#define XM_ADR_3_WIDTH 8
+#define XM_ADR_2_LBN 16
+#define XM_ADR_2_WIDTH 8
+#define XM_ADR_1_LBN 8
+#define XM_ADR_1_WIDTH 8
+#define XM_ADR_0_LBN 0
+#define XM_ADR_0_WIDTH 8
+
+/* XGMAC address register high */
+#define XM_ADR_HI_REG_MAC 0x01
+#define XM_ADR_5_LBN 8
+#define XM_ADR_5_WIDTH 8
+#define XM_ADR_4_LBN 0
+#define XM_ADR_4_WIDTH 8
+
+/* XGMAC global configuration */
+#define XM_GLB_CFG_REG_MAC 0x02
+#define XM_RX_STAT_EN_LBN 11
+#define XM_RX_STAT_EN_WIDTH 1
+#define XM_TX_STAT_EN_LBN 10
+#define XM_TX_STAT_EN_WIDTH 1
+#define XM_RX_JUMBO_MODE_LBN 6
+#define XM_RX_JUMBO_MODE_WIDTH 1
+#define XM_INTCLR_MODE_LBN 3
+#define XM_INTCLR_MODE_WIDTH 1
+#define XM_CORE_RST_LBN 0
+#define XM_CORE_RST_WIDTH 1
+
+/* XGMAC transmit configuration */
+#define XM_TX_CFG_REG_MAC 0x03
+#define XM_IPG_LBN 16
+#define XM_IPG_WIDTH 4
+#define XM_FCNTL_LBN 10
+#define XM_FCNTL_WIDTH 1
+#define XM_TXCRC_LBN 8
+#define XM_TXCRC_WIDTH 1
+#define XM_AUTO_PAD_LBN 5
+#define XM_AUTO_PAD_WIDTH 1
+#define XM_TX_PRMBL_LBN 2
+#define XM_TX_PRMBL_WIDTH 1
+#define XM_TXEN_LBN 1
+#define XM_TXEN_WIDTH 1
+
+/* XGMAC receive configuration */
+#define XM_RX_CFG_REG_MAC 0x04
+#define XM_PASS_CRC_ERR_LBN 25
+#define XM_PASS_CRC_ERR_WIDTH 1
+#define XM_ACPT_ALL_MCAST_LBN 11
+#define XM_ACPT_ALL_MCAST_WIDTH 1
+#define XM_ACPT_ALL_UCAST_LBN 9
+#define XM_ACPT_ALL_UCAST_WIDTH 1
+#define XM_AUTO_DEPAD_LBN 8
+#define XM_AUTO_DEPAD_WIDTH 1
+#define XM_RXEN_LBN 1
+#define XM_RXEN_WIDTH 1
+
+/* XGMAC management interrupt mask register */
+#define XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define XM_MSK_PRMBLE_ERR_LBN 2
+#define XM_MSK_PRMBLE_ERR_WIDTH 1
+#define XM_MSK_RMTFLT_LBN 1
+#define XM_MSK_RMTFLT_WIDTH 1
+#define XM_MSK_LCLFLT_LBN 0
+#define XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define XM_FC_REG_MAC 0x7
+#define XM_PAUSE_TIME_LBN 16
+#define XM_PAUSE_TIME_WIDTH 16
+#define XM_DIS_FCNTL_LBN 0
+#define XM_DIS_FCNTL_WIDTH 1
+
+/* XGMAC pause time count register */
+#define XM_PAUSE_TIME_REG_MAC 0x9
+
+/* XGMAC transmit parameter register */
+#define XM_TX_PARAM_REG_MAC 0x0d
+#define XM_TX_JUMBO_MODE_LBN 31
+#define XM_TX_JUMBO_MODE_WIDTH 1
+#define XM_MAX_TX_FRM_SIZE_LBN 16
+#define XM_MAX_TX_FRM_SIZE_WIDTH 14
+
+/* XGMAC receive parameter register */
+#define XM_RX_PARAM_REG_MAC 0x0e
+#define XM_MAX_RX_FRM_SIZE_LBN 0
+#define XM_MAX_RX_FRM_SIZE_WIDTH 14
+
+/* XGMAC management interrupt status register */
+#define XM_MGT_INT_REG_MAC_B0 0x0f
+#define XM_PRMBLE_ERR 2
+#define XM_PRMBLE_WIDTH 1
+#define XM_RMTFLT_LBN 1
+#define XM_RMTFLT_WIDTH 1
+#define XM_LCLFLT_LBN 0
+#define XM_LCLFLT_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset register */
+#define XX_PWR_RST_REG_MAC 0x10
+
+#define XX_PWRDND_EN_LBN 15
+#define XX_PWRDND_EN_WIDTH 1
+#define XX_PWRDNC_EN_LBN 14
+#define XX_PWRDNC_EN_WIDTH 1
+#define XX_PWRDNB_EN_LBN 13
+#define XX_PWRDNB_EN_WIDTH 1
+#define XX_PWRDNA_EN_LBN 12
+#define XX_PWRDNA_EN_WIDTH 1
+#define XX_RSTPLLCD_EN_LBN 9
+#define XX_RSTPLLCD_EN_WIDTH 1
+#define XX_RSTPLLAB_EN_LBN 8
+#define XX_RSTPLLAB_EN_WIDTH 1
+#define XX_RESETD_EN_LBN 7
+#define XX_RESETD_EN_WIDTH 1
+#define XX_RESETC_EN_LBN 6
+#define XX_RESETC_EN_WIDTH 1
+#define XX_RESETB_EN_LBN 5
+#define XX_RESETB_EN_WIDTH 1
+#define XX_RESETA_EN_LBN 4
+#define XX_RESETA_EN_WIDTH 1
+#define XX_RSTXGXSRX_EN_LBN 2
+#define XX_RSTXGXSRX_EN_WIDTH 1
+#define XX_RSTXGXSTX_EN_LBN 1
+#define XX_RSTXGXSTX_EN_WIDTH 1
+#define XX_RST_XX_EN_LBN 0
+#define XX_RST_XX_EN_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset control register */
+#define XX_SD_CTL_REG_MAC 0x11
+#define XX_HIDRVD_LBN 15
+#define XX_HIDRVD_WIDTH 1
+#define XX_LODRVD_LBN 14
+#define XX_LODRVD_WIDTH 1
+#define XX_HIDRVC_LBN 13
+#define XX_HIDRVC_WIDTH 1
+#define XX_LODRVC_LBN 12
+#define XX_LODRVC_WIDTH 1
+#define XX_HIDRVB_LBN 11
+#define XX_HIDRVB_WIDTH 1
+#define XX_LODRVB_LBN 10
+#define XX_LODRVB_WIDTH 1
+#define XX_HIDRVA_LBN 9
+#define XX_HIDRVA_WIDTH 1
+#define XX_LODRVA_LBN 8
+#define XX_LODRVA_WIDTH 1
+#define XX_LPBKD_LBN 3
+#define XX_LPBKD_WIDTH 1
+#define XX_LPBKC_LBN 2
+#define XX_LPBKC_WIDTH 1
+#define XX_LPBKB_LBN 1
+#define XX_LPBKB_WIDTH 1
+#define XX_LPBKA_LBN 0
+#define XX_LPBKA_WIDTH 1
+
+#define XX_TXDRV_CTL_REG_MAC 0x12
+#define XX_DEQD_LBN 28
+#define XX_DEQD_WIDTH 4
+#define XX_DEQC_LBN 24
+#define XX_DEQC_WIDTH 4
+#define XX_DEQB_LBN 20
+#define XX_DEQB_WIDTH 4
+#define XX_DEQA_LBN 16
+#define XX_DEQA_WIDTH 4
+#define XX_DTXD_LBN 12
+#define XX_DTXD_WIDTH 4
+#define XX_DTXC_LBN 8
+#define XX_DTXC_WIDTH 4
+#define XX_DTXB_LBN 4
+#define XX_DTXB_WIDTH 4
+#define XX_DTXA_LBN 0
+#define XX_DTXA_WIDTH 4
+
+/* XAUI XGXS core status register */
+#define XX_CORE_STAT_REG_MAC 0x16
+#define XX_FORCE_SIG_LBN 24
+#define XX_FORCE_SIG_WIDTH 8
+#define XX_FORCE_SIG_DECODE_FORCED 0xff
+#define XX_XGXS_LB_EN_LBN 23
+#define XX_XGXS_LB_EN_WIDTH 1
+#define XX_XGMII_LB_EN_LBN 22
+#define XX_XGMII_LB_EN_WIDTH 1
+#define XX_ALIGN_DONE_LBN 20
+#define XX_ALIGN_DONE_WIDTH 1
+#define XX_SYNC_STAT_LBN 16
+#define XX_SYNC_STAT_WIDTH 4
+#define XX_SYNC_STAT_DECODE_SYNCED 0xf
+#define XX_COMMA_DET_LBN 12
+#define XX_COMMA_DET_WIDTH 4
+#define XX_COMMA_DET_DECODE_DETECTED 0xf
+#define XX_COMMA_DET_RESET 0xf
+#define XX_CHARERR_LBN 4
+#define XX_CHARERR_WIDTH 4
+#define XX_CHARERR_RESET 0xf
+#define XX_DISPERR_LBN 0
+#define XX_DISPERR_WIDTH 4
+#define XX_DISPERR_RESET 0xf
+
+/* Receive filter table */
+#define RX_FILTER_TBL0 0xF00000
+
+/* Receive descriptor pointer table */
+#define RX_DESC_PTR_TBL_KER_A1 0x11800
+#define RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define RX_DESC_PTR_TBL_KER_P0 0x900
+#define RX_ISCSI_DDIG_EN_LBN 88
+#define RX_ISCSI_DDIG_EN_WIDTH 1
+#define RX_ISCSI_HDIG_EN_LBN 87
+#define RX_ISCSI_HDIG_EN_WIDTH 1
+#define RX_DESCQ_BUF_BASE_ID_LBN 36
+#define RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define RX_DESCQ_EVQ_ID_LBN 24
+#define RX_DESCQ_EVQ_ID_WIDTH 12
+#define RX_DESCQ_OWNER_ID_LBN 10
+#define RX_DESCQ_OWNER_ID_WIDTH 14
+#define RX_DESCQ_LABEL_LBN 5
+#define RX_DESCQ_LABEL_WIDTH 5
+#define RX_DESCQ_SIZE_LBN 3
+#define RX_DESCQ_SIZE_WIDTH 2
+#define RX_DESCQ_SIZE_4K 3
+#define RX_DESCQ_SIZE_2K 2
+#define RX_DESCQ_SIZE_1K 1
+#define RX_DESCQ_SIZE_512 0
+#define RX_DESCQ_TYPE_LBN 2
+#define RX_DESCQ_TYPE_WIDTH 1
+#define RX_DESCQ_JUMBO_LBN 1
+#define RX_DESCQ_JUMBO_WIDTH 1
+#define RX_DESCQ_EN_LBN 0
+#define RX_DESCQ_EN_WIDTH 1
+
+/* Transmit descriptor pointer table */
+#define TX_DESC_PTR_TBL_KER_A1 0x11900
+#define TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define TX_DESC_PTR_TBL_KER_P0 0xa40
+#define TX_NON_IP_DROP_DIS_B0_LBN 91
+#define TX_NON_IP_DROP_DIS_B0_WIDTH 1
+#define TX_IP_CHKSM_DIS_B0_LBN 90
+#define TX_IP_CHKSM_DIS_B0_WIDTH 1
+#define TX_TCP_CHKSM_DIS_B0_LBN 89
+#define TX_TCP_CHKSM_DIS_B0_WIDTH 1
+#define TX_DESCQ_EN_LBN 88
+#define TX_DESCQ_EN_WIDTH 1
+#define TX_ISCSI_DDIG_EN_LBN 87
+#define TX_ISCSI_DDIG_EN_WIDTH 1
+#define TX_ISCSI_HDIG_EN_LBN 86
+#define TX_ISCSI_HDIG_EN_WIDTH 1
+#define TX_DESCQ_BUF_BASE_ID_LBN 36
+#define TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define TX_DESCQ_EVQ_ID_LBN 24
+#define TX_DESCQ_EVQ_ID_WIDTH 12
+#define TX_DESCQ_OWNER_ID_LBN 10
+#define TX_DESCQ_OWNER_ID_WIDTH 14
+#define TX_DESCQ_LABEL_LBN 5
+#define TX_DESCQ_LABEL_WIDTH 5
+#define TX_DESCQ_SIZE_LBN 3
+#define TX_DESCQ_SIZE_WIDTH 2
+#define TX_DESCQ_SIZE_4K 3
+#define TX_DESCQ_SIZE_2K 2
+#define TX_DESCQ_SIZE_1K 1
+#define TX_DESCQ_SIZE_512 0
+#define TX_DESCQ_TYPE_LBN 1
+#define TX_DESCQ_TYPE_WIDTH 2
+
+/* Event queue pointer */
+#define EVQ_PTR_TBL_KER_A1 0x11a00
+#define EVQ_PTR_TBL_KER_B0 0xf60000
+#define EVQ_PTR_TBL_KER_P0 0x500
+#define EVQ_EN_LBN 23
+#define EVQ_EN_WIDTH 1
+#define EVQ_SIZE_LBN 20
+#define EVQ_SIZE_WIDTH 3
+#define EVQ_SIZE_32K 6
+#define EVQ_SIZE_16K 5
+#define EVQ_SIZE_8K 4
+#define EVQ_SIZE_4K 3
+#define EVQ_SIZE_2K 2
+#define EVQ_SIZE_1K 1
+#define EVQ_SIZE_512 0
+#define EVQ_BUF_BASE_ID_LBN 0
+#define EVQ_BUF_BASE_ID_WIDTH 20
+
+/* Event queue read pointer */
+#define EVQ_RPTR_REG_KER_A1 0x11b00
+#define EVQ_RPTR_REG_KER_B0 0xfa0000
+#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0)
+#define EVQ_RPTR_DWORD_LBN 0
+#define EVQ_RPTR_DWORD_WIDTH 14
+
+/* RSS indirection table */
+#define RX_RSS_INDIR_TBL_B0 0xFB0000
+#define RX_RSS_INDIR_ENT_B0_LBN 0
+#define RX_RSS_INDIR_ENT_B0_WIDTH 6
+
+/* Special buffer descriptors (full-mode) */
+#define BUF_FULL_TBL_KER_A1 0x8000
+#define BUF_FULL_TBL_KER_B0 0x800000
+#define IP_DAT_BUF_SIZE_LBN 50
+#define IP_DAT_BUF_SIZE_WIDTH 1
+#define IP_DAT_BUF_SIZE_8K 1
+#define IP_DAT_BUF_SIZE_4K 0
+#define BUF_ADR_REGION_LBN 48
+#define BUF_ADR_REGION_WIDTH 2
+#define BUF_ADR_FBUF_LBN 14
+#define BUF_ADR_FBUF_WIDTH 34
+#define BUF_OWNER_ID_FBUF_LBN 0
+#define BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* Transmit descriptor */
+#define TX_KER_PORT_LBN 63
+#define TX_KER_PORT_WIDTH 1
+#define TX_KER_CONT_LBN 62
+#define TX_KER_CONT_WIDTH 1
+#define TX_KER_BYTE_CNT_LBN 48
+#define TX_KER_BYTE_CNT_WIDTH 14
+#define TX_KER_BUF_REGION_LBN 46
+#define TX_KER_BUF_REGION_WIDTH 2
+#define TX_KER_BUF_REGION0_DECODE 0
+#define TX_KER_BUF_REGION1_DECODE 1
+#define TX_KER_BUF_REGION2_DECODE 2
+#define TX_KER_BUF_REGION3_DECODE 3
+#define TX_KER_BUF_ADR_LBN 0
+#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/* Receive descriptor */
+#define RX_KER_BUF_SIZE_LBN 48
+#define RX_KER_BUF_SIZE_WIDTH 14
+#define RX_KER_BUF_REGION_LBN 46
+#define RX_KER_BUF_REGION_WIDTH 2
+#define RX_KER_BUF_REGION0_DECODE 0
+#define RX_KER_BUF_REGION1_DECODE 1
+#define RX_KER_BUF_REGION2_DECODE 2
+#define RX_KER_BUF_REGION3_DECODE 3
+#define RX_KER_BUF_ADR_LBN 0
+#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/**************************************************************************
+ *
+ * Falcon events
+ *
+ **************************************************************************
+ */
+
+/* Event queue entries */
+#define EV_CODE_LBN 60
+#define EV_CODE_WIDTH 4
+#define RX_IP_EV_DECODE 0
+#define TX_IP_EV_DECODE 2
+#define DRIVER_EV_DECODE 5
+#define GLOBAL_EV_DECODE 6
+#define DRV_GEN_EV_DECODE 7
+#define WHOLE_EVENT_LBN 0
+#define WHOLE_EVENT_WIDTH 64
+
+/* Receive events */
+#define RX_EV_PKT_OK_LBN 56
+#define RX_EV_PKT_OK_WIDTH 1
+#define RX_EV_PAUSE_FRM_ERR_LBN 55
+#define RX_EV_PAUSE_FRM_ERR_WIDTH 1
+#define RX_EV_BUF_OWNER_ID_ERR_LBN 54
+#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define RX_EV_IF_FRAG_ERR_LBN 53
+#define RX_EV_IF_FRAG_ERR_WIDTH 1
+#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
+#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
+#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
+#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
+#define RX_EV_ETH_CRC_ERR_LBN 50
+#define RX_EV_ETH_CRC_ERR_WIDTH 1
+#define RX_EV_FRM_TRUNC_LBN 49
+#define RX_EV_FRM_TRUNC_WIDTH 1
+#define RX_EV_DRIB_NIB_LBN 48
+#define RX_EV_DRIB_NIB_WIDTH 1
+#define RX_EV_TOBE_DISC_LBN 47
+#define RX_EV_TOBE_DISC_WIDTH 1
+#define RX_EV_PKT_TYPE_LBN 44
+#define RX_EV_PKT_TYPE_WIDTH 3
+#define RX_EV_PKT_TYPE_ETH_DECODE 0
+#define RX_EV_PKT_TYPE_LLC_DECODE 1
+#define RX_EV_PKT_TYPE_JUMBO_DECODE 2
+#define RX_EV_PKT_TYPE_VLAN_DECODE 3
+#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
+#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
+#define RX_EV_HDR_TYPE_LBN 42
+#define RX_EV_HDR_TYPE_WIDTH 2
+#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
+#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
+#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
+#define RX_EV_HDR_TYPE_NON_IP_DECODE 3
+#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \
+ ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE)
+#define RX_EV_MCAST_HASH_MATCH_LBN 40
+#define RX_EV_MCAST_HASH_MATCH_WIDTH 1
+#define RX_EV_MCAST_PKT_LBN 39
+#define RX_EV_MCAST_PKT_WIDTH 1
+#define RX_EV_Q_LABEL_LBN 32
+#define RX_EV_Q_LABEL_WIDTH 5
+#define RX_EV_JUMBO_CONT_LBN 31
+#define RX_EV_JUMBO_CONT_WIDTH 1
+#define RX_EV_BYTE_CNT_LBN 16
+#define RX_EV_BYTE_CNT_WIDTH 14
+#define RX_EV_SOP_LBN 15
+#define RX_EV_SOP_WIDTH 1
+#define RX_EV_DESC_PTR_LBN 0
+#define RX_EV_DESC_PTR_WIDTH 12
+
+/* Transmit events */
+#define TX_EV_PKT_ERR_LBN 38
+#define TX_EV_PKT_ERR_WIDTH 1
+#define TX_EV_Q_LABEL_LBN 32
+#define TX_EV_Q_LABEL_WIDTH 5
+#define TX_EV_WQ_FF_FULL_LBN 15
+#define TX_EV_WQ_FF_FULL_WIDTH 1
+#define TX_EV_COMP_LBN 12
+#define TX_EV_COMP_WIDTH 1
+#define TX_EV_DESC_PTR_LBN 0
+#define TX_EV_DESC_PTR_WIDTH 12
+
+/* Driver events */
+#define DRIVER_EV_SUB_CODE_LBN 56
+#define DRIVER_EV_SUB_CODE_WIDTH 4
+#define DRIVER_EV_SUB_DATA_LBN 0
+#define DRIVER_EV_SUB_DATA_WIDTH 14
+#define TX_DESCQ_FLS_DONE_EV_DECODE 0
+#define RX_DESCQ_FLS_DONE_EV_DECODE 1
+#define EVQ_INIT_DONE_EV_DECODE 2
+#define EVQ_NOT_EN_EV_DECODE 3
+#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4
+#define SRM_UPD_DONE_EV_DECODE 5
+#define WAKE_UP_EV_DECODE 6
+#define TX_PKT_NON_TCP_UDP_DECODE 9
+#define TIMER_EV_DECODE 10
+#define RX_RECOVERY_EV_DECODE 11
+#define RX_DSC_ERROR_EV_DECODE 14
+#define TX_DSC_ERROR_EV_DECODE 15
+#define DRIVER_EV_TX_DESCQ_ID_LBN 0
+#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
+#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12
+#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
+#define DRIVER_EV_RX_DESCQ_ID_LBN 0
+#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
+#define SRM_CLR_EV_DECODE 0
+#define SRM_UPD_EV_DECODE 1
+#define SRM_ILLCLR_EV_DECODE 2
+
+/* Global events */
+#define RX_RECOVERY_B0_LBN 12
+#define RX_RECOVERY_B0_WIDTH 1
+#define XG_MNT_INTR_B0_LBN 11
+#define XG_MNT_INTR_B0_WIDTH 1
+#define RX_RECOVERY_A1_LBN 11
+#define RX_RECOVERY_A1_WIDTH 1
+#define XG_PHY_INTR_LBN 9
+#define XG_PHY_INTR_WIDTH 1
+#define G_PHY1_INTR_LBN 8
+#define G_PHY1_INTR_WIDTH 1
+#define G_PHY0_INTR_LBN 7
+#define G_PHY0_INTR_WIDTH 1
+
+/* Driver-generated test events */
+#define EVQ_MAGIC_LBN 0
+#define EVQ_MAGIC_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ *
+ */
+#define GRxGoodOct_offset 0x0
+#define GRxBadOct_offset 0x8
+#define GRxMissPkt_offset 0x10
+#define GRxFalseCRS_offset 0x14
+#define GRxPausePkt_offset 0x18
+#define GRxBadPkt_offset 0x1C
+#define GRxUcastPkt_offset 0x20
+#define GRxMcastPkt_offset 0x24
+#define GRxBcastPkt_offset 0x28
+#define GRxGoodLt64Pkt_offset 0x2C
+#define GRxBadLt64Pkt_offset 0x30
+#define GRx64Pkt_offset 0x34
+#define GRx65to127Pkt_offset 0x38
+#define GRx128to255Pkt_offset 0x3C
+#define GRx256to511Pkt_offset 0x40
+#define GRx512to1023Pkt_offset 0x44
+#define GRx1024to15xxPkt_offset 0x48
+#define GRx15xxtoJumboPkt_offset 0x4C
+#define GRxGtJumboPkt_offset 0x50
+#define GRxFcsErr64to15xxPkt_offset 0x54
+#define GRxFcsErr15xxtoJumboPkt_offset 0x58
+#define GRxFcsErrGtJumboPkt_offset 0x5C
+#define GTxGoodBadOct_offset 0x80
+#define GTxGoodOct_offset 0x88
+#define GTxSglColPkt_offset 0x90
+#define GTxMultColPkt_offset 0x94
+#define GTxExColPkt_offset 0x98
+#define GTxDefPkt_offset 0x9C
+#define GTxLateCol_offset 0xA0
+#define GTxExDefPkt_offset 0xA4
+#define GTxPausePkt_offset 0xA8
+#define GTxBadPkt_offset 0xAC
+#define GTxUcastPkt_offset 0xB0
+#define GTxMcastPkt_offset 0xB4
+#define GTxBcastPkt_offset 0xB8
+#define GTxLt64Pkt_offset 0xBC
+#define GTx64Pkt_offset 0xC0
+#define GTx65to127Pkt_offset 0xC4
+#define GTx128to255Pkt_offset 0xC8
+#define GTx256to511Pkt_offset 0xCC
+#define GTx512to1023Pkt_offset 0xD0
+#define GTx1024to15xxPkt_offset 0xD4
+#define GTx15xxtoJumboPkt_offset 0xD8
+#define GTxGtJumboPkt_offset 0xDC
+#define GTxNonTcpUdpPkt_offset 0xE0
+#define GTxMacSrcErrPkt_offset 0xE4
+#define GTxIpSrcErrPkt_offset 0xE8
+#define GDmaDone_offset 0xEC
+
+#define XgRxOctets_offset 0x0
+#define XgRxOctets_WIDTH 48
+#define XgRxOctetsOK_offset 0x8
+#define XgRxOctetsOK_WIDTH 48
+#define XgRxPkts_offset 0x10
+#define XgRxPkts_WIDTH 32
+#define XgRxPktsOK_offset 0x14
+#define XgRxPktsOK_WIDTH 32
+#define XgRxBroadcastPkts_offset 0x18
+#define XgRxBroadcastPkts_WIDTH 32
+#define XgRxMulticastPkts_offset 0x1C
+#define XgRxMulticastPkts_WIDTH 32
+#define XgRxUnicastPkts_offset 0x20
+#define XgRxUnicastPkts_WIDTH 32
+#define XgRxUndersizePkts_offset 0x24
+#define XgRxUndersizePkts_WIDTH 32
+#define XgRxOversizePkts_offset 0x28
+#define XgRxOversizePkts_WIDTH 32
+#define XgRxJabberPkts_offset 0x2C
+#define XgRxJabberPkts_WIDTH 32
+#define XgRxUndersizeFCSerrorPkts_offset 0x30
+#define XgRxUndersizeFCSerrorPkts_WIDTH 32
+#define XgRxDropEvents_offset 0x34
+#define XgRxDropEvents_WIDTH 32
+#define XgRxFCSerrorPkts_offset 0x38
+#define XgRxFCSerrorPkts_WIDTH 32
+#define XgRxAlignError_offset 0x3C
+#define XgRxAlignError_WIDTH 32
+#define XgRxSymbolError_offset 0x40
+#define XgRxSymbolError_WIDTH 32
+#define XgRxInternalMACError_offset 0x44
+#define XgRxInternalMACError_WIDTH 32
+#define XgRxControlPkts_offset 0x48
+#define XgRxControlPkts_WIDTH 32
+#define XgRxPausePkts_offset 0x4C
+#define XgRxPausePkts_WIDTH 32
+#define XgRxPkts64Octets_offset 0x50
+#define XgRxPkts64Octets_WIDTH 32
+#define XgRxPkts65to127Octets_offset 0x54
+#define XgRxPkts65to127Octets_WIDTH 32
+#define XgRxPkts128to255Octets_offset 0x58
+#define XgRxPkts128to255Octets_WIDTH 32
+#define XgRxPkts256to511Octets_offset 0x5C
+#define XgRxPkts256to511Octets_WIDTH 32
+#define XgRxPkts512to1023Octets_offset 0x60
+#define XgRxPkts512to1023Octets_WIDTH 32
+#define XgRxPkts1024to15xxOctets_offset 0x64
+#define XgRxPkts1024to15xxOctets_WIDTH 32
+#define XgRxPkts15xxtoMaxOctets_offset 0x68
+#define XgRxPkts15xxtoMaxOctets_WIDTH 32
+#define XgRxLengthError_offset 0x6C
+#define XgRxLengthError_WIDTH 32
+#define XgTxPkts_offset 0x80
+#define XgTxPkts_WIDTH 32
+#define XgTxOctets_offset 0x88
+#define XgTxOctets_WIDTH 48
+#define XgTxMulticastPkts_offset 0x90
+#define XgTxMulticastPkts_WIDTH 32
+#define XgTxBroadcastPkts_offset 0x94
+#define XgTxBroadcastPkts_WIDTH 32
+#define XgTxUnicastPkts_offset 0x98
+#define XgTxUnicastPkts_WIDTH 32
+#define XgTxControlPkts_offset 0x9C
+#define XgTxControlPkts_WIDTH 32
+#define XgTxPausePkts_offset 0xA0
+#define XgTxPausePkts_WIDTH 32
+#define XgTxPkts64Octets_offset 0xA4
+#define XgTxPkts64Octets_WIDTH 32
+#define XgTxPkts65to127Octets_offset 0xA8
+#define XgTxPkts65to127Octets_WIDTH 32
+#define XgTxPkts128to255Octets_offset 0xAC
+#define XgTxPkts128to255Octets_WIDTH 32
+#define XgTxPkts256to511Octets_offset 0xB0
+#define XgTxPkts256to511Octets_WIDTH 32
+#define XgTxPkts512to1023Octets_offset 0xB4
+#define XgTxPkts512to1023Octets_WIDTH 32
+#define XgTxPkts1024to15xxOctets_offset 0xB8
+#define XgTxPkts1024to15xxOctets_WIDTH 32
+#define XgTxPkts1519toMaxOctets_offset 0xBC
+#define XgTxPkts1519toMaxOctets_WIDTH 32
+#define XgTxUndersizePkts_offset 0xC0
+#define XgTxUndersizePkts_WIDTH 32
+#define XgTxOversizePkts_offset 0xC4
+#define XgTxOversizePkts_WIDTH 32
+#define XgTxNonTcpUdpPkt_offset 0xC8
+#define XgTxNonTcpUdpPkt_WIDTH 16
+#define XgTxMacSrcErrPkt_offset 0xCC
+#define XgTxMacSrcErrPkt_WIDTH 16
+#define XgTxIpSrcErrPkt_offset 0xD0
+#define XgTxIpSrcErrPkt_WIDTH 16
+#define XgDmaDone_offset 0xD4
+
+#define FALCON_STATS_NOT_DONE 0x00000000
+#define FALCON_STATS_DONE 0xffffffff
+
+/* Interrupt status register bits */
+#define FATAL_INT_LBN 64
+#define FATAL_INT_WIDTH 1
+#define INT_EVQS_LBN 40
+#define INT_EVQS_WIDTH 4
+
+/**************************************************************************
+ *
+ * Falcon non-volatile configuration
+ *
+ **************************************************************************
+ */
+
+/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
+struct falcon_nvconfig_board_v2 {
+ __le16 nports;
+ u8 port0_phy_addr;
+ u8 port0_phy_type;
+ u8 port1_phy_addr;
+ u8 port1_phy_type;
+ __le16 asic_sub_revision;
+ __le16 board_revision;
+} __attribute__ ((packed));
+
+#define NVCONFIG_BASE 0x300
+#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
+struct falcon_nvconfig {
+ efx_oword_t ee_vpd_cfg_reg; /* 0x300 */
+ u8 mac_address[2][8]; /* 0x310 */
+ efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */
+ efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */
+ efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */
+ efx_oword_t hw_init_reg; /* 0x350 */
+ efx_oword_t nic_stat_reg; /* 0x360 */
+ efx_oword_t glb_ctl_reg; /* 0x370 */
+ efx_oword_t srm_cfg_reg; /* 0x380 */
+ efx_oword_t spare_reg; /* 0x390 */
+ __le16 board_magic_num; /* 0x3A0 */
+ __le16 board_struct_ver;
+ __le16 board_checksum;
+ struct falcon_nvconfig_board_v2 board_v2;
+} __attribute__ ((packed));
+
+#endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
new file mode 100644
index 000000000000..ea08184ddfa9
--- /dev/null
+++ b/drivers/net/sfc/falcon_io.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_IO_H
+#define EFX_FALCON_IO_H
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Falcon hardware access
+ *
+ **************************************************************************
+ *
+ * Notes on locking strategy:
+ *
+ * Most Falcon registers require 16-byte (or 8-byte, for SRAM
+ * registers) atomic writes which necessitates locking.
+ * Under normal operation few writes to the Falcon BAR are made and these
+ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
+ * cased to allow 4-byte (hence lockless) accesses.
+ *
+ * It *is* safe to write to these 4-byte registers in the middle of an
+ * access to an 8-byte or 16-byte register. We therefore use a
+ * spinlock to protect accesses to the larger registers, but no locks
+ * for the 4-byte registers.
+ *
+ * A write barrier is needed to ensure that DW3 is written after DW0/1/2
+ * due to the way the 16byte registers are "collected" in the Falcon BIU
+ *
+ * We also lock when carrying out reads, to ensure consistency of the
+ * data (made possible since the BIU reads all 128 bits into a cache).
+ * Reads are very rare, so this isn't a significant performance
+ * impact. (Most data transferred from NIC to host is DMAed directly
+ * into host memory).
+ *
+ * I/O BAR access uses locks for both reads and writes (but is only provided
+ * for testing purposes).
+ */
+
+/* Special buffer descriptors (Falcon SRAM) */
+#define BUF_TBL_KER_A1 0x18000
+#define BUF_TBL_KER_B0 0x800000
+
+
+#if BITS_PER_LONG == 64
+#define FALCON_USE_QWORD_IO 1
+#endif
+
+#define _falcon_writeq(efx, value, reg) \
+ __raw_writeq((__force u64) (value), (efx)->membase + (reg))
+#define _falcon_writel(efx, value, reg) \
+ __raw_writel((__force u32) (value), (efx)->membase + (reg))
+#define _falcon_readq(efx, reg) \
+ ((__force __le64) __raw_readq((efx)->membase + (reg)))
+#define _falcon_readl(efx, reg) \
+ ((__force __le32) __raw_readl((efx)->membase + (reg)))
+
+/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
+static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags;
+
+ EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ _falcon_writeq(efx, value->u64[0], reg + 0);
+ wmb();
+ _falcon_writeq(efx, value->u64[1], reg + 8);
+#else
+ _falcon_writel(efx, value->u32[0], reg + 0);
+ _falcon_writel(efx, value->u32[1], reg + 4);
+ _falcon_writel(efx, value->u32[2], reg + 8);
+ wmb();
+ _falcon_writel(efx, value->u32[3], reg + 12);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
+static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
+ unsigned long flags;
+
+ EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
+ reg, EFX_QWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ _falcon_writeq(efx, value->u64[0], reg + 0);
+#else
+ _falcon_writel(efx, value->u32[0], reg + 0);
+ wmb();
+ _falcon_writel(efx, value->u32[1], reg + 4);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write dword to Falcon register that allows partial writes
+ *
+ * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
+ * TX_DESC_UPD_REG) can be written to as a single dword. This allows
+ * for lockless writes.
+ */
+static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+
+ /* No lock required */
+ _falcon_writel(efx, value->u32[0], reg);
+}
+
+/* Read from a Falcon register
+ *
+ * This reads an entire 16-byte Falcon register in one go, locking as
+ * appropriate. It is essential to read the first dword first, as this
+ * prompts Falcon to load the current value into the shadow register.
+ */
+static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ value->u32[0] = _falcon_readl(efx, reg + 0);
+ rmb();
+ value->u32[1] = _falcon_readl(efx, reg + 4);
+ value->u32[2] = _falcon_readl(efx, reg + 8);
+ value->u32[3] = _falcon_readl(efx, reg + 12);
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+}
+
+/* This reads an 8-byte Falcon SRAM entry in one go. */
+static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ value->u64[0] = _falcon_readq(efx, reg + 0);
+#else
+ value->u32[0] = _falcon_readl(efx, reg + 0);
+ rmb();
+ value->u32[1] = _falcon_readl(efx, reg + 4);
+#endif
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
+ reg, EFX_QWORD_VAL(*value));
+}
+
+/* Read dword from Falcon register that allows partial writes (sic) */
+static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ value->u32[0] = _falcon_readl(efx, reg);
+ EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+}
+
+/* Write to a register forming part of a table */
+static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Read to a register forming part of a table */
+static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Write to a dword register forming part of a table */
+static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Page-mapped register block size */
+#define FALCON_PAGE_BLOCK_SIZE 0x2000
+
+/* Calculate offset to page-mapped register block */
+#define FALCON_PAGED_REG(page, reg) \
+ ((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
+
+/* As for falcon_write(), but for a page-mapped register. */
+static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
+}
+
+/* As for falcon_writel(), but for a page-mapped register. */
+static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
+}
+
+/* Write dword to Falcon page-mapped register with an extra lock.
+ *
+ * As for falcon_writel_page(), but for a register that suffers from
+ * SFC bug 3181. Take out a lock so the BIU collector cannot be
+ * confused. */
+static inline void falcon_writel_page_locked(struct efx_nic *efx,
+ efx_dword_t *value,
+ unsigned int reg,
+ unsigned int page)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+#endif /* EFX_FALCON_IO_H */
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
new file mode 100644
index 000000000000..a74b7931a3c4
--- /dev/null
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -0,0 +1,655 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "mac.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "boards.h"
+#include "workarounds.h"
+
+/**************************************************************************
+ *
+ * MAC register access
+ *
+ **************************************************************************/
+
+/* Offset of an XMAC register within Falcon */
+#define FALCON_XMAC_REG(mac_reg) \
+ (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
+
+void falcon_xmac_writel(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg)
+{
+ efx_oword_t temp;
+
+ EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
+ falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
+}
+
+void falcon_xmac_readl(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg)
+{
+ efx_oword_t temp;
+
+ falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
+ EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
+}
+
+/**************************************************************************
+ *
+ * MAC operations
+ *
+ *************************************************************************/
+static int falcon_reset_xmac(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int count;
+
+ EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
+ falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+
+ for (count = 0; count < 10000; count++) { /* wait upto 100ms */
+ falcon_xmac_readl(efx, &reg, XM_GLB_CFG_REG_MAC);
+ if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
+ return 0;
+ udelay(10);
+ }
+
+ /* This often fails when DSP is disabled, ignore it */
+ if (sfe4001_phy_flash_cfg != 0)
+ return 0;
+
+ EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
+ return -ETIMEDOUT;
+}
+
+/* Configure the XAUI driver that is an output from Falcon */
+static void falcon_setup_xaui(struct efx_nic *efx)
+{
+ efx_dword_t sdctl, txdrv;
+
+ /* Move the XAUI into low power, unless there is no PHY, in
+ * which case the XAUI will have to drive a cable. */
+ if (efx->phy_type == PHY_TYPE_NONE)
+ return;
+
+ falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
+ falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
+
+ EFX_POPULATE_DWORD_8(txdrv,
+ XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+ XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+ falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
+}
+
+static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ EFX_ZERO_DWORD(reg);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+}
+
+static int _falcon_reset_xaui_a(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ falcon_hold_xaui_in_rst(efx);
+ falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
+
+ /* Follow the RAMBUS XAUI data reset sequencing
+ * Channels A and B first: power down, reset PLL, reset, clear
+ */
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Channels C and D: power down, reset PLL, reset, clear */
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Setup XAUI */
+ falcon_setup_xaui(efx);
+ udelay(10);
+
+ /* Take XGXS out of reset */
+ EFX_ZERO_DWORD(reg);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ return 0;
+}
+
+static int _falcon_reset_xaui_b(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int count;
+
+ EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+
+ /* Give some time for the link to establish */
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
+ if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
+ falcon_setup_xaui(efx);
+ return 0;
+ }
+ udelay(10);
+ }
+ EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
+ return -ETIMEDOUT;
+}
+
+int falcon_reset_xaui(struct efx_nic *efx)
+{
+ int rc;
+
+ if (EFX_WORKAROUND_9388(efx)) {
+ falcon_hold_xaui_in_rst(efx);
+ efx->phy_op->reset_xaui(efx);
+ rc = _falcon_reset_xaui_a(efx);
+ } else {
+ rc = _falcon_reset_xaui_b(efx);
+ }
+ return rc;
+}
+
+static int falcon_xgmii_status(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return 1;
+
+ /* The ISR latches, so clear it and re-read */
+ falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+ falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+
+ if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
+ EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
+ EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
+ return 0;
+ }
+
+ return 1;
+}
+
+static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
+{
+ efx_dword_t reg;
+
+ if ((FALCON_REV(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+ return;
+
+ /* Flush the ISR */
+ if (enable)
+ falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+
+ EFX_POPULATE_DWORD_2(reg,
+ XM_MSK_RMTFLT, !enable,
+ XM_MSK_LCLFLT, !enable);
+ falcon_xmac_writel(efx, &reg, XM_MGT_INT_MSK_REG_MAC_B0);
+}
+
+int falcon_init_xmac(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Initialize the PHY first so the clock is around */
+ rc = efx->phy_op->init(efx);
+ if (rc)
+ goto fail1;
+
+ rc = falcon_reset_xaui(efx);
+ if (rc)
+ goto fail2;
+
+ /* Wait again. Give the PHY and MAC time to come back */
+ schedule_timeout_uninterruptible(HZ / 10);
+
+ rc = falcon_reset_xmac(efx);
+ if (rc)
+ goto fail2;
+
+ falcon_mask_status_intr(efx, 1);
+ return 0;
+
+ fail2:
+ efx->phy_op->fini(efx);
+ fail1:
+ return rc;
+}
+
+int falcon_xaui_link_ok(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int align_done, sync_status, link_ok = 0;
+
+ if (LOOPBACK_INTERNAL(efx))
+ return 1;
+
+ /* Read link status */
+ falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+
+ align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
+ sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
+ if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
+ link_ok = 1;
+
+ /* Clear link status ready for next read */
+ EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
+ EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
+ EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
+ falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
+
+ /* If the link is up, then check the phy side of the xaui link
+ * (error conditions from the wire side propoagate back through
+ * the phy to the xaui side). */
+ if (efx->link_up && link_ok) {
+ int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
+ if (has_phyxs)
+ link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
+ }
+
+ /* If the PHY and XAUI links are up, then check the mac's xgmii
+ * fault state */
+ if (efx->link_up && link_ok)
+ link_ok = falcon_xgmii_status(efx);
+
+ return link_ok;
+}
+
+static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+{
+ unsigned int max_frame_len;
+ efx_dword_t reg;
+ int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+
+ /* Configure MAC - cut-thru mode is hard wired on */
+ EFX_POPULATE_DWORD_3(reg,
+ XM_RX_JUMBO_MODE, 1,
+ XM_TX_STAT_EN, 1,
+ XM_RX_STAT_EN, 1);
+ falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+
+ /* Configure TX */
+ EFX_POPULATE_DWORD_6(reg,
+ XM_TXEN, 1,
+ XM_TX_PRMBL, 1,
+ XM_AUTO_PAD, 1,
+ XM_TXCRC, 1,
+ XM_FCNTL, 1,
+ XM_IPG, 0x3);
+ falcon_xmac_writel(efx, &reg, XM_TX_CFG_REG_MAC);
+
+ /* Configure RX */
+ EFX_POPULATE_DWORD_5(reg,
+ XM_RXEN, 1,
+ XM_AUTO_DEPAD, 0,
+ XM_ACPT_ALL_MCAST, 1,
+ XM_ACPT_ALL_UCAST, efx->promiscuous,
+ XM_PASS_CRC_ERR, 1);
+ falcon_xmac_writel(efx, &reg, XM_RX_CFG_REG_MAC);
+
+ /* Set frame length */
+ max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
+ EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
+ falcon_xmac_writel(efx, &reg, XM_RX_PARAM_REG_MAC);
+ EFX_POPULATE_DWORD_2(reg,
+ XM_MAX_TX_FRM_SIZE, max_frame_len,
+ XM_TX_JUMBO_MODE, 1);
+ falcon_xmac_writel(efx, &reg, XM_TX_PARAM_REG_MAC);
+
+ EFX_POPULATE_DWORD_2(reg,
+ XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
+ XM_DIS_FCNTL, rx_fc ? 0 : 1);
+ falcon_xmac_writel(efx, &reg, XM_FC_REG_MAC);
+
+ /* Set MAC address */
+ EFX_POPULATE_DWORD_4(reg,
+ XM_ADR_0, efx->net_dev->dev_addr[0],
+ XM_ADR_1, efx->net_dev->dev_addr[1],
+ XM_ADR_2, efx->net_dev->dev_addr[2],
+ XM_ADR_3, efx->net_dev->dev_addr[3]);
+ falcon_xmac_writel(efx, &reg, XM_ADR_LO_REG_MAC);
+ EFX_POPULATE_DWORD_2(reg,
+ XM_ADR_4, efx->net_dev->dev_addr[4],
+ XM_ADR_5, efx->net_dev->dev_addr[5]);
+ falcon_xmac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
+}
+
+static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS) ? 1 : 0;
+ int xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI) ? 1 : 0;
+ int xgmii_loopback =
+ (efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
+
+ /* XGXS block is flaky and will need to be reset if moving
+ * into our out of XGMII, XGXS or XAUI loopbacks. */
+ if (EFX_WORKAROUND_5147(efx)) {
+ int old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
+ int reset_xgxs;
+
+ falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+ old_xgxs_loopback = EFX_DWORD_FIELD(reg, XX_XGXS_LB_EN);
+ old_xgmii_loopback = EFX_DWORD_FIELD(reg, XX_XGMII_LB_EN);
+
+ falcon_xmac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
+ old_xaui_loopback = EFX_DWORD_FIELD(reg, XX_LPBKA);
+
+ /* The PHY driver may have turned XAUI off */
+ reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
+ (xaui_loopback != old_xaui_loopback) ||
+ (xgmii_loopback != old_xgmii_loopback));
+ if (reset_xgxs) {
+ falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(1);
+ }
+ }
+
+ falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
+ EFX_SET_DWORD_FIELD(reg, XX_FORCE_SIG,
+ (xgxs_loopback || xaui_loopback) ?
+ XX_FORCE_SIG_DECODE_FORCED : 0);
+ EFX_SET_DWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
+ EFX_SET_DWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
+ falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
+
+ falcon_xmac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
+ EFX_SET_DWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
+ EFX_SET_DWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
+ EFX_SET_DWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
+ EFX_SET_DWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
+ falcon_xmac_writel(efx, &reg, XX_SD_CTL_REG_MAC);
+}
+
+
+/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
+ * to come back up. Bash it until it comes back up */
+static int falcon_check_xaui_link_up(struct efx_nic *efx)
+{
+ int max_tries, tries;
+ tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
+ max_tries = tries;
+
+ if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
+ (efx->phy_type == PHY_TYPE_NONE))
+ return 0;
+
+ while (tries) {
+ if (falcon_xaui_link_ok(efx))
+ return 1;
+
+ EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
+ __func__, tries);
+ (void) falcon_reset_xaui(efx);
+ udelay(200);
+ tries--;
+ }
+
+ EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n",
+ max_tries);
+ return 0;
+}
+
+void falcon_reconfigure_xmac(struct efx_nic *efx)
+{
+ int xaui_link_ok;
+
+ falcon_mask_status_intr(efx, 0);
+
+ falcon_deconfigure_mac_wrapper(efx);
+
+ efx->tx_disabled = LOOPBACK_INTERNAL(efx);
+ efx->phy_op->reconfigure(efx);
+
+ falcon_reconfigure_xgxs_core(efx);
+ falcon_reconfigure_xmac_core(efx);
+
+ falcon_reconfigure_mac_wrapper(efx);
+
+ /* Ensure XAUI link is up */
+ xaui_link_ok = falcon_check_xaui_link_up(efx);
+
+ if (xaui_link_ok && efx->link_up)
+ falcon_mask_status_intr(efx, 1);
+}
+
+void falcon_fini_xmac(struct efx_nic *efx)
+{
+ /* Isolate the MAC - PHY */
+ falcon_deconfigure_mac_wrapper(efx);
+
+ /* Potentially power down the PHY */
+ efx->phy_op->fini(efx);
+}
+
+void falcon_update_stats_xmac(struct efx_nic *efx)
+{
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ int rc;
+
+ rc = falcon_dma_stats(efx, XgDmaDone_offset);
+ if (rc)
+ return;
+
+ /* Update MAC stats from DMAed values */
+ FALCON_STAT(efx, XgRxOctets, rx_bytes);
+ FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
+ FALCON_STAT(efx, XgRxPkts, rx_packets);
+ FALCON_STAT(efx, XgRxPktsOK, rx_good);
+ FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
+ FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
+ FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
+ FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
+ FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
+ FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
+ FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
+ FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
+ FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
+ FALCON_STAT(efx, XgRxAlignError, rx_align_error);
+ FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
+ FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
+ FALCON_STAT(efx, XgRxControlPkts, rx_control);
+ FALCON_STAT(efx, XgRxPausePkts, rx_pause);
+ FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
+ FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
+ FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
+ FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
+ FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
+ FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
+ FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
+ FALCON_STAT(efx, XgRxLengthError, rx_length_error);
+ FALCON_STAT(efx, XgTxPkts, tx_packets);
+ FALCON_STAT(efx, XgTxOctets, tx_bytes);
+ FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
+ FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
+ FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
+ FALCON_STAT(efx, XgTxControlPkts, tx_control);
+ FALCON_STAT(efx, XgTxPausePkts, tx_pause);
+ FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
+ FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
+ FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
+ FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
+ FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
+ FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
+ FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
+ FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
+ FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
+ FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
+ FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
+ FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);
+
+ /* Update derived statistics */
+ mac_stats->tx_good_bytes =
+ (mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
+ mac_stats->rx_bad_bytes =
+ (mac_stats->rx_bytes - mac_stats->rx_good_bytes);
+}
+
+int falcon_check_xmac(struct efx_nic *efx)
+{
+ unsigned xaui_link_ok;
+ int rc;
+
+ if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
+ (efx->phy_type == PHY_TYPE_NONE))
+ return 0;
+
+ falcon_mask_status_intr(efx, 0);
+ xaui_link_ok = falcon_xaui_link_ok(efx);
+
+ if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
+ (void) falcon_reset_xaui(efx);
+
+ /* Call the PHY check_hw routine */
+ rc = efx->phy_op->check_hw(efx);
+
+ /* Unmask interrupt if everything was (and still is) ok */
+ if (xaui_link_ok && efx->link_up)
+ falcon_mask_status_intr(efx, 1);
+
+ return rc;
+}
+
+/* Simulate a PHY event */
+void falcon_xmac_sim_phy_event(struct efx_nic *efx)
+{
+ efx_qword_t phy_event;
+
+ EFX_POPULATE_QWORD_2(phy_event,
+ EV_CODE, GLOBAL_EV_DECODE,
+ XG_PHY_INTR, 1);
+ falcon_generate_event(&efx->channel[0], &phy_event);
+}
+
+int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ mdio_clause45_get_settings(efx, ecmd);
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->phy_address = efx->mii.phy_id;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->duplex = DUPLEX_FULL;
+ return 0;
+}
+
+int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ if (ecmd->transceiver != XCVR_INTERNAL)
+ return -EINVAL;
+ if (ecmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (ecmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ return mdio_clause45_set_settings(efx, ecmd);
+}
+
+
+int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
+{
+ int reset;
+
+ if (flow_control & EFX_FC_AUTO) {
+ EFX_LOG(efx, "10G does not support flow control "
+ "autonegotiation\n");
+ return -EINVAL;
+ }
+
+ if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
+ return -EINVAL;
+
+ /* TX flow control may automatically turn itself off if the
+ * link partner (intermittently) stops responding to pause
+ * frames. There isn't any indication that this has happened,
+ * so the best we do is leave it up to the user to spot this
+ * and fix it be cycling transmit flow control on this end. */
+ reset = ((flow_control & EFX_FC_TX) &&
+ !(efx->flow_control & EFX_FC_TX));
+ if (EFX_WORKAROUND_11482(efx) && reset) {
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ /* Recover by resetting the EM block */
+ if (efx->link_up)
+ falcon_drain_tx_fifo(efx);
+ } else {
+ /* Schedule a reset to recover */
+ efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
+ }
+ }
+
+ efx->flow_control = flow_control;
+
+ return 0;
+}
diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h
new file mode 100644
index 000000000000..d25bbd1297f4
--- /dev/null
+++ b/drivers/net/sfc/gmii.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_GMII_H
+#define EFX_GMII_H
+
+/*
+ * GMII interface
+ */
+
+#include <linux/mii.h>
+
+/* GMII registers, excluding registers already defined as MII
+ * registers in mii.h
+ */
+#define GMII_IER 0x12 /* Interrupt enable register */
+#define GMII_ISR 0x13 /* Interrupt status register */
+
+/* Interrupt enable register */
+#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
+#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
+#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
+#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */
+#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
+#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */
+#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */
+#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
+#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
+#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
+#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
+#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */
+#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
+#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
+#define IER_JABBER 0x0001 /* Bit 0 - jabber */
+
+/* Interrupt status register */
+#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
+#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
+#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
+#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */
+#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
+#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */
+#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */
+#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
+#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
+#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
+#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
+#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */
+#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
+#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
+#define ISR_JABBER 0x0001 /* Bit 0 - jabber */
+
+/* Logically extended advertisement register */
+#define GM_ADVERTISE_SLCT ADVERTISE_SLCT
+#define GM_ADVERTISE_CSMA ADVERTISE_CSMA
+#define GM_ADVERTISE_10HALF ADVERTISE_10HALF
+#define GM_ADVERTISE_1000XFULL ADVERTISE_1000XFULL
+#define GM_ADVERTISE_10FULL ADVERTISE_10FULL
+#define GM_ADVERTISE_1000XHALF ADVERTISE_1000XHALF
+#define GM_ADVERTISE_100HALF ADVERTISE_100HALF
+#define GM_ADVERTISE_1000XPAUSE ADVERTISE_1000XPAUSE
+#define GM_ADVERTISE_100FULL ADVERTISE_100FULL
+#define GM_ADVERTISE_1000XPSE_ASYM ADVERTISE_1000XPSE_ASYM
+#define GM_ADVERTISE_100BASE4 ADVERTISE_100BASE4
+#define GM_ADVERTISE_PAUSE_CAP ADVERTISE_PAUSE_CAP
+#define GM_ADVERTISE_PAUSE_ASYM ADVERTISE_PAUSE_ASYM
+#define GM_ADVERTISE_RESV ADVERTISE_RESV
+#define GM_ADVERTISE_RFAULT ADVERTISE_RFAULT
+#define GM_ADVERTISE_LPACK ADVERTISE_LPACK
+#define GM_ADVERTISE_NPAGE ADVERTISE_NPAGE
+#define GM_ADVERTISE_1000FULL (ADVERTISE_1000FULL << 8)
+#define GM_ADVERTISE_1000HALF (ADVERTISE_1000HALF << 8)
+#define GM_ADVERTISE_1000 (GM_ADVERTISE_1000FULL | \
+ GM_ADVERTISE_1000HALF)
+#define GM_ADVERTISE_FULL (GM_ADVERTISE_1000FULL | \
+ ADVERTISE_FULL)
+#define GM_ADVERTISE_ALL (GM_ADVERTISE_1000FULL | \
+ GM_ADVERTISE_1000HALF | \
+ ADVERTISE_ALL)
+
+/* Logically extended link partner ability register */
+#define GM_LPA_SLCT LPA_SLCT
+#define GM_LPA_10HALF LPA_10HALF
+#define GM_LPA_1000XFULL LPA_1000XFULL
+#define GM_LPA_10FULL LPA_10FULL
+#define GM_LPA_1000XHALF LPA_1000XHALF
+#define GM_LPA_100HALF LPA_100HALF
+#define GM_LPA_1000XPAUSE LPA_1000XPAUSE
+#define GM_LPA_100FULL LPA_100FULL
+#define GM_LPA_1000XPAUSE_ASYM LPA_1000XPAUSE_ASYM
+#define GM_LPA_100BASE4 LPA_100BASE4
+#define GM_LPA_PAUSE_CAP LPA_PAUSE_CAP
+#define GM_LPA_PAUSE_ASYM LPA_PAUSE_ASYM
+#define GM_LPA_RESV LPA_RESV
+#define GM_LPA_RFAULT LPA_RFAULT
+#define GM_LPA_LPACK LPA_LPACK
+#define GM_LPA_NPAGE LPA_NPAGE
+#define GM_LPA_1000FULL (LPA_1000FULL << 6)
+#define GM_LPA_1000HALF (LPA_1000HALF << 6)
+#define GM_LPA_10000FULL 0x00040000
+#define GM_LPA_10000HALF 0x00080000
+#define GM_LPA_DUPLEX (GM_LPA_1000FULL | GM_LPA_10000FULL \
+ | LPA_DUPLEX)
+#define GM_LPA_10 (LPA_10FULL | LPA_10HALF)
+#define GM_LPA_100 LPA_100
+#define GM_LPA_1000 (GM_LPA_1000FULL | GM_LPA_1000HALF)
+#define GM_LPA_10000 (GM_LPA_10000FULL | GM_LPA_10000HALF)
+
+/* Retrieve GMII autonegotiation advertised abilities
+ *
+ * The MII advertisment register (MII_ADVERTISE) is logically extended
+ * to include advertisement bits ADVERTISE_1000FULL and
+ * ADVERTISE_1000HALF from MII_CTRL1000. The result can be tested
+ * against the GM_ADVERTISE_xxx constants.
+ */
+static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
+{
+ unsigned int advertise;
+ unsigned int ctrl1000;
+
+ advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
+ ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
+ return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
+}
+
+/* Retrieve GMII autonegotiation link partner abilities
+ *
+ * The MII link partner ability register (MII_LPA) is logically
+ * extended by adding bits LPA_1000HALF and LPA_1000FULL from
+ * MII_STAT1000. The result can be tested against the GM_LPA_xxx
+ * constants.
+ */
+static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
+{
+ unsigned int lpa;
+ unsigned int stat1000;
+
+ lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
+ stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
+ return (((stat1000 << 6) & GM_LPA_1000) | lpa);
+}
+
+/* Calculate GMII autonegotiated link technology
+ *
+ * "negotiated" should be the result of gmii_advertised() logically
+ * ANDed with the result of gmii_lpa().
+ *
+ * "tech" will be negotiated with the unused bits masked out. For
+ * example, if both ends of the link are capable of both
+ * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
+ * out.
+ */
+static inline unsigned int gmii_nway_result(unsigned int negotiated)
+{
+ unsigned int other_bits;
+
+ /* Mask out the speed and duplexity bits */
+ other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
+
+ if (negotiated & GM_LPA_1000FULL)
+ return (other_bits | GM_LPA_1000FULL);
+ else if (negotiated & GM_LPA_1000HALF)
+ return (other_bits | GM_LPA_1000HALF);
+ else
+ return (other_bits | mii_nway_result(negotiated));
+}
+
+/* Calculate GMII non-autonegotiated link technology
+ *
+ * This provides an equivalent to gmii_nway_result for the case when
+ * autonegotiation is disabled.
+ */
+static inline unsigned int gmii_forced_result(unsigned int bmcr)
+{
+ unsigned int result;
+ int full_duplex;
+
+ full_duplex = bmcr & BMCR_FULLDPLX;
+ if (bmcr & BMCR_SPEED1000)
+ result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
+ else if (bmcr & BMCR_SPEED100)
+ result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
+ else
+ result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
+ return result;
+}
+
+#endif /* EFX_GMII_H */
diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c
new file mode 100644
index 000000000000..b6c62d0ed9c2
--- /dev/null
+++ b/drivers/net/sfc/i2c-direct.c
@@ -0,0 +1,381 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "i2c-direct.h"
+
+/*
+ * I2C data (SDA) and clock (SCL) line read/writes with appropriate
+ * delays.
+ */
+
+static inline void setsda(struct efx_i2c_interface *i2c, int state)
+{
+ udelay(i2c->op->udelay);
+ i2c->sda = state;
+ i2c->op->setsda(i2c);
+ udelay(i2c->op->udelay);
+}
+
+static inline void setscl(struct efx_i2c_interface *i2c, int state)
+{
+ udelay(i2c->op->udelay);
+ i2c->scl = state;
+ i2c->op->setscl(i2c);
+ udelay(i2c->op->udelay);
+}
+
+static inline int getsda(struct efx_i2c_interface *i2c)
+{
+ int sda;
+
+ udelay(i2c->op->udelay);
+ sda = i2c->op->getsda(i2c);
+ udelay(i2c->op->udelay);
+ return sda;
+}
+
+static inline int getscl(struct efx_i2c_interface *i2c)
+{
+ int scl;
+
+ udelay(i2c->op->udelay);
+ scl = i2c->op->getscl(i2c);
+ udelay(i2c->op->udelay);
+ return scl;
+}
+
+/*
+ * I2C low-level protocol operations
+ *
+ */
+
+static inline void i2c_release(struct efx_i2c_interface *i2c)
+{
+ EFX_WARN_ON_PARANOID(!i2c->scl);
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ /* Devices may time out if operations do not end */
+ setscl(i2c, 1);
+ setsda(i2c, 1);
+ EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
+ EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
+}
+
+static inline void i2c_start(struct efx_i2c_interface *i2c)
+{
+ /* We may be restarting immediately after a {send,recv}_bit,
+ * so SCL will not necessarily already be high.
+ */
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ setscl(i2c, 1);
+ setsda(i2c, 0);
+ setscl(i2c, 0);
+ setsda(i2c, 1);
+}
+
+static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
+{
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ setsda(i2c, bit);
+ setscl(i2c, 1);
+ setscl(i2c, 0);
+ setsda(i2c, 1);
+}
+
+static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
+{
+ int bit;
+
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ setscl(i2c, 1);
+ bit = getsda(i2c);
+ setscl(i2c, 0);
+ return bit;
+}
+
+static inline void i2c_stop(struct efx_i2c_interface *i2c)
+{
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ setsda(i2c, 0);
+ setscl(i2c, 1);
+ setsda(i2c, 1);
+}
+
+/*
+ * I2C mid-level protocol operations
+ *
+ */
+
+/* Sends a byte via the I2C bus and checks for an acknowledgement from
+ * the slave device.
+ */
+static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
+{
+ int i;
+
+ /* Send byte */
+ for (i = 0; i < 8; i++) {
+ i2c_send_bit(i2c, !!(byte & 0x80));
+ byte <<= 1;
+ }
+
+ /* Check for acknowledgement from slave */
+ return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
+}
+
+/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
+static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
+{
+ u8 value = 0;
+ int i;
+
+ /* Receive byte */
+ for (i = 0; i < 8; i++)
+ value = (value << 1) | i2c_recv_bit(i2c);
+
+ /* Send ACK/NACK */
+ i2c_send_bit(i2c, (ack ? 0 : 1));
+
+ return value;
+}
+
+/* Calculate command byte for a read operation */
+static inline u8 i2c_read_cmd(u8 device_id)
+{
+ return ((device_id << 1) | 1);
+}
+
+/* Calculate command byte for a write operation */
+static inline u8 i2c_write_cmd(u8 device_id)
+{
+ return ((device_id << 1) | 0);
+}
+
+int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
+{
+ int rc;
+
+ /* If someone is driving the bus low we just give up. */
+ if (getsda(i2c) == 0 || getscl(i2c) == 0) {
+ EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
+ " Giving up.\n", __func__);
+ return -EFAULT;
+ }
+
+ /* Pretend to initiate a device write */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* This performs a fast read of one or more consecutive bytes from an
+ * I2C device. Not all devices support consecutive reads of more than
+ * one byte; for these devices use efx_i2c_read() instead.
+ */
+int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(data == NULL);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device and starting offset */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+ rc = i2c_send_byte(i2c, offset);
+ if (rc)
+ goto out;
+
+ /* Read data from device */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
+ if (rc)
+ goto out;
+ for (i = 0; i < (len - 1); i++)
+ /* Read and acknowledge all but the last byte */
+ data[i] = i2c_recv_byte(i2c, 1);
+ /* Read last byte with no acknowledgement */
+ data[i] = i2c_recv_byte(i2c, 0);
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* This performs a fast write of one or more consecutive bytes to an
+ * I2C device. Not all devices support consecutive writes of more
+ * than one byte; for these devices use efx_i2c_write() instead.
+ */
+int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device and starting offset */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+ rc = i2c_send_byte(i2c, offset);
+ if (rc)
+ goto out;
+
+ /* Write data to device */
+ for (i = 0; i < len; i++) {
+ rc = i2c_send_byte(i2c, data[i]);
+ if (rc)
+ goto out;
+ }
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* I2C byte-by-byte read */
+int efx_i2c_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ int rc;
+
+ /* i2c_fast_read with length 1 is a single byte read */
+ for (; len > 0; offset++, data++, len--) {
+ rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/* I2C byte-by-byte write */
+int efx_i2c_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, const u8 *data, unsigned int len)
+{
+ int rc;
+
+ /* i2c_fast_write with length 1 is a single byte write */
+ for (; len > 0; offset++, data++, len--) {
+ rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
+ if (rc)
+ return rc;
+ mdelay(i2c->op->mdelay);
+ }
+
+ return 0;
+}
+
+
+/* This is just a slightly neater wrapper round efx_i2c_fast_write
+ * in the case where the target doesn't take an offset
+ */
+int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
+ u8 device_id, const u8 *data, unsigned int len)
+{
+ return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
+}
+
+/* I2C receiving of bytes - does not send an offset byte */
+int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ u8 *bytes, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device */
+ i2c_start(i2c);
+
+ /* Read data from device */
+ rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
+ if (rc)
+ goto out;
+
+ for (i = 0; i < (len - 1); i++)
+ /* Read and acknowledge all but the last byte */
+ bytes[i] = i2c_recv_byte(i2c, 1);
+ /* Read last byte with no acknowledgement */
+ bytes[i] = i2c_recv_byte(i2c, 0);
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* SMBus and some I2C devices will time out if the I2C clock is
+ * held low for too long. This is most likely to happen in virtualised
+ * systems (when the entire domain is descheduled) but could in
+ * principle happen due to preemption on any busy system (and given the
+ * potential length of an I2C operation turning preemption off is not
+ * a sensible option). The following functions deal with the failure by
+ * retrying up to a fixed number of times.
+ */
+
+#define I2C_MAX_RETRIES (10)
+
+/* The timeout problem will result in -EIO. If the wrapped function
+ * returns any other error, pass this up and do not retry. */
+#define RETRY_WRAPPER(_f) \
+ int retries = I2C_MAX_RETRIES; \
+ int rc; \
+ while (retries) { \
+ rc = _f; \
+ if (rc != -EIO) \
+ return rc; \
+ retries--; \
+ } \
+ return rc; \
+
+int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
+{
+ RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
+}
+
+int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
+}
+
+int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, const u8 *data, unsigned int len)
+{
+ RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
+}
diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h
new file mode 100644
index 000000000000..291e561071f5
--- /dev/null
+++ b/drivers/net/sfc/i2c-direct.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_I2C_DIRECT_H
+#define EFX_I2C_DIRECT_H
+
+#include "net_driver.h"
+
+/*
+ * Direct control of an I2C bus
+ */
+
+struct efx_i2c_interface;
+
+/**
+ * struct efx_i2c_bit_operations - I2C bus direct control methods
+ *
+ * I2C bus direct control methods.
+ *
+ * @setsda: Set state of SDA line
+ * @setscl: Set state of SCL line
+ * @getsda: Get state of SDA line
+ * @getscl: Get state of SCL line
+ * @udelay: Delay between each bit operation
+ * @mdelay: Delay between each byte write
+ */
+struct efx_i2c_bit_operations {
+ void (*setsda) (struct efx_i2c_interface *i2c);
+ void (*setscl) (struct efx_i2c_interface *i2c);
+ int (*getsda) (struct efx_i2c_interface *i2c);
+ int (*getscl) (struct efx_i2c_interface *i2c);
+ unsigned int udelay;
+ unsigned int mdelay;
+};
+
+/**
+ * struct efx_i2c_interface - an I2C interface
+ *
+ * An I2C interface.
+ *
+ * @efx: Attached Efx NIC
+ * @op: I2C bus control methods
+ * @sda: Current output state of SDA line
+ * @scl: Current output state of SCL line
+ */
+struct efx_i2c_interface {
+ struct efx_nic *efx;
+ struct efx_i2c_bit_operations *op;
+ unsigned int sda:1;
+ unsigned int scl:1;
+};
+
+extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
+extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ u8 *data, unsigned int len);
+extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+extern int efx_i2c_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len);
+extern int efx_i2c_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+
+extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ const u8 *bytes, unsigned int len);
+
+extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ u8 *bytes, unsigned int len);
+
+
+/* Versions of the API that retry on failure. */
+extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
+ u8 device_id);
+
+extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len);
+
+extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+
+#endif /* EFX_I2C_DIRECT_H */
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
new file mode 100644
index 000000000000..edd07d4dee18
--- /dev/null
+++ b/drivers/net/sfc/mac.h
@@ -0,0 +1,33 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_MAC_H
+#define EFX_MAC_H
+
+#include "net_driver.h"
+
+extern void falcon_xmac_writel(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg);
+extern void falcon_xmac_readl(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg);
+extern int falcon_init_xmac(struct efx_nic *efx);
+extern void falcon_reconfigure_xmac(struct efx_nic *efx);
+extern void falcon_update_stats_xmac(struct efx_nic *efx);
+extern void falcon_fini_xmac(struct efx_nic *efx);
+extern int falcon_check_xmac(struct efx_nic *efx);
+extern void falcon_xmac_sim_phy_event(struct efx_nic *efx);
+extern int falcon_xmac_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+extern int falcon_xmac_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+extern int falcon_xmac_set_pause(struct efx_nic *efx,
+ enum efx_fc_type pause_params);
+
+#endif
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
new file mode 100644
index 000000000000..c4f540e93b79
--- /dev/null
+++ b/drivers/net/sfc/mdio_10g.c
@@ -0,0 +1,360 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+/*
+ * Useful functions for working with MDIO clause 45 PHYs
+ */
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "mdio_10g.h"
+#include "boards.h"
+
+int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
+ int spins, int spintime)
+{
+ u32 ctrl;
+ int phy_id = port->mii.phy_id;
+
+ /* Catch callers passing values in the wrong units (or just silly) */
+ EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
+
+ mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
+ (1 << MDIO_MMDREG_CTRL1_RESET_LBN));
+ /* Wait for the reset bit to clear. */
+ do {
+ msleep(spintime);
+ ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
+ spins--;
+
+ } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
+
+ return spins ? spins : -ETIMEDOUT;
+}
+
+static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
+ int fault_fatal)
+{
+ int status;
+ int phy_id = efx->mii.phy_id;
+
+ if (LOOPBACK_INTERNAL(efx))
+ return 0;
+
+ /* Read MMD STATUS2 to check it is responding. */
+ status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
+ if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
+ ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
+ MDIO_MMDREG_STAT2_PRESENT_VAL) {
+ EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
+ return -EIO;
+ }
+
+ /* Read MMD STATUS 1 to check for fault. */
+ status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
+ if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
+ if (fault_fatal) {
+ EFX_ERR(efx, "PHY MMD %d reporting fatal"
+ " fault: status %x\n", mmd, status);
+ return -EIO;
+ } else {
+ EFX_LOG(efx, "PHY MMD %d reporting status"
+ " %x (expected)\n", mmd, status);
+ }
+ }
+ return 0;
+}
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TIME 1000 /* ms */
+#define MDIO45_RESET_ITERS 100
+
+int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask)
+{
+ const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
+ int tries = MDIO45_RESET_ITERS;
+ int rc = 0;
+ int in_reset;
+
+ while (tries) {
+ int mask = mmd_mask;
+ int mmd = 0;
+ int stat;
+ in_reset = 0;
+ while (mask) {
+ if (mask & 1) {
+ stat = mdio_clause45_read(efx,
+ efx->mii.phy_id,
+ mmd,
+ MDIO_MMDREG_CTRL1);
+ if (stat < 0) {
+ EFX_ERR(efx, "failed to read status of"
+ " MMD %d\n", mmd);
+ return -EIO;
+ }
+ if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+ in_reset |= (1 << mmd);
+ }
+ mask = mask >> 1;
+ mmd++;
+ }
+ if (!in_reset)
+ break;
+ tries--;
+ msleep(spintime);
+ }
+ if (in_reset != 0) {
+ EFX_ERR(efx, "not all MMDs came out of reset in time."
+ " MMDs still in reset: %x\n", in_reset);
+ rc = -ETIMEDOUT;
+ }
+ return rc;
+}
+
+int mdio_clause45_check_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask, unsigned int fatal_mask)
+{
+ int devices, mmd = 0;
+ int probe_mmd;
+
+ /* Historically we have probed the PHYXS to find out what devices are
+ * present,but that doesn't work so well if the PHYXS isn't expected
+ * to exist, if so just find the first item in the list supplied. */
+ probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
+ __ffs(mmd_mask);
+ devices = mdio_clause45_read(efx, efx->mii.phy_id,
+ probe_mmd, MDIO_MMDREG_DEVS0);
+
+ /* Check all the expected MMDs are present */
+ if (devices < 0) {
+ EFX_ERR(efx, "failed to read devices present\n");
+ return -EIO;
+ }
+ if ((devices & mmd_mask) != mmd_mask) {
+ EFX_ERR(efx, "required MMDs not present: got %x, "
+ "wanted %x\n", devices, mmd_mask);
+ return -ENODEV;
+ }
+ EFX_TRACE(efx, "Devices present: %x\n", devices);
+
+ /* Check all required MMDs are responding and happy. */
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ int fault_fatal = fatal_mask & 1;
+ if (mdio_clause45_check_mmd(efx, mmd, fault_fatal))
+ return -EIO;
+ }
+ mmd_mask = mmd_mask >> 1;
+ fatal_mask = fatal_mask >> 1;
+ mmd++;
+ }
+
+ return 0;
+}
+
+int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
+{
+ int phy_id = efx->mii.phy_id;
+ int status;
+ int ok = 1;
+ int mmd = 0;
+ int good;
+
+ /* If the port is in loopback, then we should only consider a subset
+ * of mmd's */
+ if (LOOPBACK_INTERNAL(efx))
+ return 1;
+ else if (efx->loopback_mode == LOOPBACK_NETWORK)
+ return 0;
+ else if (efx->loopback_mode == LOOPBACK_PHYXS)
+ mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS |
+ MDIO_MMDREG_DEVS0_PCS |
+ MDIO_MMDREG_DEVS0_PMAPMD);
+ else if (efx->loopback_mode == LOOPBACK_PCS)
+ mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS |
+ MDIO_MMDREG_DEVS0_PMAPMD);
+ else if (efx->loopback_mode == LOOPBACK_PMAPMD)
+ mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD;
+
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ /* Double reads because link state is latched, and a
+ * read moves the current state into the register */
+ status = mdio_clause45_read(efx, phy_id,
+ mmd, MDIO_MMDREG_STAT1);
+ status = mdio_clause45_read(efx, phy_id,
+ mmd, MDIO_MMDREG_STAT1);
+
+ good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+ ok = ok && good;
+ }
+ mmd_mask = (mmd_mask >> 1);
+ mmd++;
+ }
+ return ok;
+}
+
+void mdio_clause45_transmit_disable(struct efx_nic *efx)
+{
+ int phy_id = efx->mii.phy_id;
+ int ctrl1, ctrl2;
+
+ ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_MMDREG_TXDIS);
+ if (efx->tx_disabled)
+ ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
+ else
+ ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
+ if (ctrl1 != ctrl2)
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_MMDREG_TXDIS, ctrl2);
+}
+
+void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
+{
+ int phy_id = efx->mii.phy_id;
+ int ctrl1, ctrl2;
+
+ /* Handle (with debouncing) PMA/PMD loopback */
+ ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_MMDREG_CTRL1);
+
+ if (efx->loopback_mode == LOOPBACK_PMAPMD)
+ ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
+ else
+ ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
+
+ if (ctrl1 != ctrl2)
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_MMDREG_CTRL1, ctrl2);
+
+ /* Handle (with debouncing) PCS loopback */
+ ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
+ MDIO_MMDREG_CTRL1);
+ if (efx->loopback_mode == LOOPBACK_PCS)
+ ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+ else
+ ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+
+ if (ctrl1 != ctrl2)
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS,
+ MDIO_MMDREG_CTRL1, ctrl2);
+
+ /* Handle (with debouncing) PHYXS network loopback */
+ ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
+ MDIO_MMDREG_CTRL1);
+ if (efx->loopback_mode == LOOPBACK_NETWORK)
+ ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+ else
+ ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+
+ if (ctrl1 != ctrl2)
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
+ MDIO_MMDREG_CTRL1, ctrl2);
+}
+
+/**
+ * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
+ * @efx: Efx NIC
+ * @ecmd: Buffer for settings
+ *
+ * On return the 'port', 'speed', 'supported' and 'advertising' fields of
+ * ecmd have been filled out based on the PMA type.
+ */
+void mdio_clause45_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd)
+{
+ int pma_type;
+
+ /* If no PMA is present we are presumably talking something XAUI-ish
+ * like CX4. Which we report as FIBRE (see below) */
+ if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ return;
+ }
+
+ pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
+ pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
+
+ switch (pma_type) {
+ /* We represent CX4 as fibre in the absence of anything
+ better. */
+ case MDIO_PMAPMD_CTRL2_10G_CX4:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ break;
+ /* 10G Base-T */
+ case MDIO_PMAPMD_CTRL2_10G_BT:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_10000baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_1G_BT:
+ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_1000baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_100_BT:
+ ecmd->speed = SPEED_100;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_100baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_10_BT:
+ ecmd->speed = SPEED_10;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
+ ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
+ break;
+ /* All the other defined modes are flavours of
+ * 10G optical */
+ default:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ break;
+ }
+}
+
+/**
+ * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
+ * @efx: Efx NIC
+ * @ecmd: New settings
+ *
+ * Currently this just enforces that we are _not_ changing the
+ * 'port', 'speed', 'supported' or 'advertising' settings as these
+ * cannot be changed on any currently supported PHY.
+ */
+int mdio_clause45_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd)
+{
+ struct ethtool_cmd tmpcmd;
+ mdio_clause45_get_settings(efx, &tmpcmd);
+ /* None of the current PHYs support more than one mode
+ * of operation (and only 10GBT ever will), so keep things
+ * simple for now */
+ if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
+ (ecmd->supported == tmpcmd.supported) &&
+ (ecmd->advertising == tmpcmd.advertising))
+ return 0;
+ return -EOPNOTSUPP;
+}
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
new file mode 100644
index 000000000000..cb99f3f4491c
--- /dev/null
+++ b/drivers/net/sfc/mdio_10g.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_MDIO_10G_H
+#define EFX_MDIO_10G_H
+
+/*
+ * Definitions needed for doing 10G MDIO as specified in clause 45
+ * MDIO, which do not appear in Linux yet. Also some helper functions.
+ */
+
+#include "efx.h"
+#include "boards.h"
+
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD (1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS (2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS (3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS (4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS (5)
+/* Transmission convergence */
+#define MDIO_MMD_TC (6)
+/* Auto negotiation */
+#define MDIO_MMD_AN (7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1 (0)
+#define MDIO_MMDREG_STAT1 (1)
+#define MDIO_MMDREG_IDHI (2)
+#define MDIO_MMDREG_IDLOW (3)
+#define MDIO_MMDREG_SPEED (4)
+#define MDIO_MMDREG_DEVS0 (5)
+#define MDIO_MMDREG_DEVS1 (6)
+#define MDIO_MMDREG_CTRL2 (7)
+#define MDIO_MMDREG_STAT2 (8)
+#define MDIO_MMDREG_TXDIS (9)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
+/* Loopback */
+/* Loopback bit for WIS, PCS, PHYSX and DTEXS */
+#define MDIO_MMDREG_CTRL1_LBACK_LBN (14)
+#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN (2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
+/* Low power ability */
+#define MDIO_MMDREG_STAT1_LPABLE_LBN (1)
+#define MDIO_MMDREG_STAT1_LPABLE_WIDTH (1)
+
+/* Bits in ID reg */
+#define MDIO_ID_REV(_id32) (_id32 & 0xf)
+#define MDIO_ID_MODEL(_id32) ((_id32 >> 4) & 0x3f)
+#define MDIO_ID_OUI(_id32) (_id32 >> 10)
+
+/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
+ * so the 'bit present' bit number of an MMD is the number of
+ * that MMD */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* Bits in MMDREG_TXDIS */
+#define MDIO_MMDREG_TXDIS_GLOBAL_LBN (0)
+#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH (1)
+
+/* MMD-specific bits, ordered by MMD, then register */
+#define MDIO_PMAPMD_CTRL1_LBACK_LBN (0)
+#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH (1)
+
+/* PMA type (4 bits) */
+#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0)
+#define MDIO_PMAPMD_CTRL2_10G_EW (0x1)
+#define MDIO_PMAPMD_CTRL2_10G_LW (0x2)
+#define MDIO_PMAPMD_CTRL2_10G_SW (0x3)
+#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4)
+#define MDIO_PMAPMD_CTRL2_10G_ER (0x5)
+#define MDIO_PMAPMD_CTRL2_10G_LR (0x6)
+#define MDIO_PMAPMD_CTRL2_10G_SR (0x7)
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_10G_BT (0x9)
+/* Reserved */
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_1G_BT (0xc)
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_100_BT (0xe)
+#define MDIO_PMAPMD_CTRL2_10_BT (0xf)
+#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf)
+
+/* PHY XGXS lane state */
+#define MDIO_PHYXS_LANE_STATE (0x18)
+#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
+
+/* AN registers */
+#define MDIO_AN_STATUS (1)
+#define MDIO_AN_STATUS_XNP_LBN (7)
+#define MDIO_AN_STATUS_PAGE_LBN (6)
+#define MDIO_AN_STATUS_AN_DONE_LBN (5)
+#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0)
+
+#define MDIO_AN_10GBT_STATUS (33)
+#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
+#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */
+#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
+#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
+#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
+#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
+#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */
+
+
+/* Packing of the prt and dev arguments of clause 45 style MDIO into a
+ * single int so they can be passed into the mdio_read/write functions
+ * that currently exist. Note that as Falcon is the only current user,
+ * the packed form is chosen to match what Falcon needs to write into
+ * a register. This is checked at compile-time so do not change it. If
+ * your target chip needs things layed out differently you will need
+ * to unpack the arguments in your chip-specific mdio functions.
+ */
+ /* These are defined by the standard. */
+#define MDIO45_PRT_ID_WIDTH (5)
+#define MDIO45_DEV_ID_WIDTH (5)
+
+/* The prt ID is just packed in immediately to the left of the dev ID */
+#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
+
+#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
+/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
+#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1)
+#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
+#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1))
+
+
+#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH
+#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH
+#define MDIO45_DEV_ID_COMP_LBN 0
+#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH
+
+/* Compose port and device into a phy_id */
+static inline int mdio_clause45_pack(u8 prt, u8 dev)
+{
+ efx_dword_t phy_id;
+ EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
+ MDIO45_DEV_ID_COMP, dev);
+ return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
+}
+
+static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
+{
+ efx_dword_t phy_id;
+ EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
+ *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
+ *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
+}
+
+static inline int mdio_clause45_read(struct efx_nic *efx,
+ u8 prt, u8 dev, u16 addr)
+{
+ return efx->mii.mdio_read(efx->net_dev,
+ mdio_clause45_pack(prt, dev), addr);
+}
+
+static inline void mdio_clause45_write(struct efx_nic *efx,
+ u8 prt, u8 dev, u16 addr, int value)
+{
+ efx->mii.mdio_write(efx->net_dev,
+ mdio_clause45_pack(prt, dev), addr, value);
+}
+
+
+static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
+{
+ int phy_id = efx->mii.phy_id;
+ u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
+ u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
+ return (id_hi << 16) | (id_low);
+}
+
+static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
+{
+ int i, sync, lane_status;
+
+ for (i = 0; i < 2; ++i)
+ lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PHYXS,
+ MDIO_PHYXS_LANE_STATE);
+
+ sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
+ if (!sync)
+ EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
+ return sync;
+}
+
+extern const char *mdio_clause45_mmd_name(int mmd);
+
+/*
+ * Reset a specific MMD and wait for reset to clear.
+ * Return number of spins left (>0) on success, -%ETIMEDOUT on failure.
+ *
+ * This function will sleep
+ */
+extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
+ int spins, int spintime);
+
+/* As mdio_clause45_check_mmd but for multiple MMDs */
+int mdio_clause45_check_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask, unsigned int fatal_mask);
+
+/* Check the link status of specified mmds in bit mask */
+extern int mdio_clause45_links_ok(struct efx_nic *efx,
+ unsigned int mmd_mask);
+
+/* Generic transmit disable support though PMAPMD */
+extern void mdio_clause45_transmit_disable(struct efx_nic *efx);
+
+/* Generic part of reconfigure: set/clear loopback bits */
+extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
+
+/* Read (some of) the PHY settings over MDIO */
+extern void mdio_clause45_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+
+/* Set (some of) the PHY settings over MDIO */
+extern int mdio_clause45_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+
+/* Wait for specified MMDs to exit reset within a timeout */
+extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask);
+
+#endif /* EFX_MDIO_10G_H */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
new file mode 100644
index 000000000000..59f261b4171f
--- /dev/null
+++ b/drivers/net/sfc/net_driver.h
@@ -0,0 +1,909 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+/* Common definitions for all Efx net driver code */
+
+#ifndef EFX_NET_DRIVER_H
+#define EFX_NET_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/timer.h>
+#include <linux/mii.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/workqueue.h>
+#include <linux/inet_lro.h>
+
+#include "enum.h"
+#include "bitfield.h"
+#include "i2c-direct.h"
+
+#define EFX_MAX_LRO_DESCRIPTORS 8
+#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
+
+/**************************************************************************
+ *
+ * Build definitions
+ *
+ **************************************************************************/
+#ifndef EFX_DRIVER_NAME
+#define EFX_DRIVER_NAME "sfc"
+#endif
+#define EFX_DRIVER_VERSION "2.2.0136"
+
+#ifdef EFX_ENABLE_DEBUG
+#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
+#define EFX_WARN_ON_PARANOID(x) WARN_ON(x)
+#else
+#define EFX_BUG_ON_PARANOID(x) do {} while (0)
+#define EFX_WARN_ON_PARANOID(x) do {} while (0)
+#endif
+
+#define NET_DEV_REGISTERED(efx) \
+ ((efx)->net_dev->reg_state == NETREG_REGISTERED)
+
+/* Include net device name in log messages if it has been registered.
+ * Use efx->name not efx->net_dev->name so that races with (un)registration
+ * are harmless.
+ */
+#define NET_DEV_NAME(efx) (NET_DEV_REGISTERED(efx) ? (efx)->name : "")
+
+/* Un-rate-limited logging */
+#define EFX_ERR(efx, fmt, args...) \
+dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
+
+#define EFX_INFO(efx, fmt, args...) \
+dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
+
+#ifdef EFX_ENABLE_DEBUG
+#define EFX_LOG(efx, fmt, args...) \
+dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+#else
+#define EFX_LOG(efx, fmt, args...) \
+dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+#endif
+
+#define EFX_TRACE(efx, fmt, args...) do {} while (0)
+
+#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
+
+/* Rate-limited logging */
+#define EFX_ERR_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
+
+#define EFX_INFO_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
+
+#define EFX_LOG_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
+
+/* Kernel headers may redefine inline anyway */
+#ifndef inline
+#define inline inline __attribute__ ((always_inline))
+#endif
+
+/**************************************************************************
+ *
+ * Efx data structures
+ *
+ **************************************************************************/
+
+#define EFX_MAX_CHANNELS 32
+#define EFX_MAX_TX_QUEUES 1
+#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
+
+/**
+ * struct efx_special_buffer - An Efx special buffer
+ * @addr: CPU base address of the buffer
+ * @dma_addr: DMA base address of the buffer
+ * @len: Buffer length, in bytes
+ * @index: Buffer index within controller;s buffer table
+ * @entries: Number of buffer table entries
+ *
+ * Special buffers are used for the event queues and the TX and RX
+ * descriptor queues for each channel. They are *not* used for the
+ * actual transmit and receive buffers.
+ *
+ * Note that for Falcon, TX and RX descriptor queues live in host memory.
+ * Allocation and freeing procedures must take this into account.
+ */
+struct efx_special_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ unsigned int len;
+ int index;
+ int entries;
+};
+
+/**
+ * struct efx_tx_buffer - An Efx TX buffer
+ * @skb: The associated socket buffer.
+ * Set only on the final fragment of a packet; %NULL for all other
+ * fragments. When this fragment completes, then we can free this
+ * skb.
+ * @tsoh: The associated TSO header structure, or %NULL if this
+ * buffer is not a TSO header.
+ * @dma_addr: DMA address of the fragment.
+ * @len: Length of this fragment.
+ * This field is zero when the queue slot is empty.
+ * @continuation: True if this fragment is not the end of a packet.
+ * @unmap_single: True if pci_unmap_single should be used.
+ * @unmap_addr: DMA address to unmap
+ * @unmap_len: Length of this fragment to unmap
+ */
+struct efx_tx_buffer {
+ const struct sk_buff *skb;
+ struct efx_tso_header *tsoh;
+ dma_addr_t dma_addr;
+ unsigned short len;
+ unsigned char continuation;
+ unsigned char unmap_single;
+ dma_addr_t unmap_addr;
+ unsigned short unmap_len;
+};
+
+/**
+ * struct efx_tx_queue - An Efx TX queue
+ *
+ * This is a ring buffer of TX fragments.
+ * Since the TX completion path always executes on the same
+ * CPU and the xmit path can operate on different CPUs,
+ * performance is increased by ensuring that the completion
+ * path and the xmit path operate on different cache lines.
+ * This is particularly important if the xmit path is always
+ * executing on one CPU which is different from the completion
+ * path. There is also a cache line for members which are
+ * read but not written on the fast path.
+ *
+ * @efx: The associated Efx NIC
+ * @queue: DMA queue number
+ * @used: Queue is used by net driver
+ * @channel: The associated channel
+ * @buffer: The software buffer ring
+ * @txd: The hardware descriptor ring
+ * @read_count: Current read pointer.
+ * This is the number of buffers that have been removed from both rings.
+ * @stopped: Stopped flag.
+ * Set if this TX queue is currently stopping its port.
+ * @insert_count: Current insert pointer
+ * This is the number of buffers that have been added to the
+ * software ring.
+ * @write_count: Current write pointer
+ * This is the number of buffers that have been added to the
+ * hardware ring.
+ * @old_read_count: The value of read_count when last checked.
+ * This is here for performance reasons. The xmit path will
+ * only get the up-to-date value of read_count if this
+ * variable indicates that the queue is full. This is to
+ * avoid cache-line ping-pong between the xmit path and the
+ * completion path.
+ * @tso_headers_free: A list of TSO headers allocated for this TX queue
+ * that are not in use, and so available for new TSO sends. The list
+ * is protected by the TX queue lock.
+ * @tso_bursts: Number of times TSO xmit invoked by kernel
+ * @tso_long_headers: Number of packets with headers too long for standard
+ * blocks
+ * @tso_packets: Number of packets via the TSO xmit path
+ */
+struct efx_tx_queue {
+ /* Members which don't change on the fast path */
+ struct efx_nic *efx ____cacheline_aligned_in_smp;
+ int queue;
+ int used;
+ struct efx_channel *channel;
+ struct efx_nic *nic;
+ struct efx_tx_buffer *buffer;
+ struct efx_special_buffer txd;
+
+ /* Members used mainly on the completion path */
+ unsigned int read_count ____cacheline_aligned_in_smp;
+ int stopped;
+
+ /* Members used only on the xmit path */
+ unsigned int insert_count ____cacheline_aligned_in_smp;
+ unsigned int write_count;
+ unsigned int old_read_count;
+ struct efx_tso_header *tso_headers_free;
+ unsigned int tso_bursts;
+ unsigned int tso_long_headers;
+ unsigned int tso_packets;
+};
+
+/**
+ * struct efx_rx_buffer - An Efx RX data buffer
+ * @dma_addr: DMA base address of the buffer
+ * @skb: The associated socket buffer, if any.
+ * If both this and page are %NULL, the buffer slot is currently free.
+ * @page: The associated page buffer, if any.
+ * If both this and skb are %NULL, the buffer slot is currently free.
+ * @data: Pointer to ethernet header
+ * @len: Buffer length, in bytes.
+ * @unmap_addr: DMA address to unmap
+ */
+struct efx_rx_buffer {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+ struct page *page;
+ char *data;
+ unsigned int len;
+ dma_addr_t unmap_addr;
+};
+
+/**
+ * struct efx_rx_queue - An Efx RX queue
+ * @efx: The associated Efx NIC
+ * @queue: DMA queue number
+ * @used: Queue is used by net driver
+ * @channel: The associated channel
+ * @buffer: The software buffer ring
+ * @rxd: The hardware descriptor ring
+ * @added_count: Number of buffers added to the receive queue.
+ * @notified_count: Number of buffers given to NIC (<= @added_count).
+ * @removed_count: Number of buffers removed from the receive queue.
+ * @add_lock: Receive queue descriptor add spin lock.
+ * This lock must be held in order to add buffers to the RX
+ * descriptor ring (rxd and buffer) and to update added_count (but
+ * not removed_count).
+ * @max_fill: RX descriptor maximum fill level (<= ring size)
+ * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
+ * (<= @max_fill)
+ * @fast_fill_limit: The level to which a fast fill will fill
+ * (@fast_fill_trigger <= @fast_fill_limit <= @max_fill)
+ * @min_fill: RX descriptor minimum non-zero fill level.
+ * This records the minimum fill level observed when a ring
+ * refill was triggered.
+ * @min_overfill: RX descriptor minimum overflow fill level.
+ * This records the minimum fill level at which RX queue
+ * overflow was observed. It should never be set.
+ * @alloc_page_count: RX allocation strategy counter.
+ * @alloc_skb_count: RX allocation strategy counter.
+ * @work: Descriptor push work thread
+ * @buf_page: Page for next RX buffer.
+ * We can use a single page for multiple RX buffers. This tracks
+ * the remaining space in the allocation.
+ * @buf_dma_addr: Page's DMA address.
+ * @buf_data: Page's host address.
+ */
+struct efx_rx_queue {
+ struct efx_nic *efx;
+ int queue;
+ int used;
+ struct efx_channel *channel;
+ struct efx_rx_buffer *buffer;
+ struct efx_special_buffer rxd;
+
+ int added_count;
+ int notified_count;
+ int removed_count;
+ spinlock_t add_lock;
+ unsigned int max_fill;
+ unsigned int fast_fill_trigger;
+ unsigned int fast_fill_limit;
+ unsigned int min_fill;
+ unsigned int min_overfill;
+ unsigned int alloc_page_count;
+ unsigned int alloc_skb_count;
+ struct delayed_work work;
+ unsigned int slow_fill_count;
+
+ struct page *buf_page;
+ dma_addr_t buf_dma_addr;
+ char *buf_data;
+};
+
+/**
+ * struct efx_buffer - An Efx general-purpose buffer
+ * @addr: host base address of the buffer
+ * @dma_addr: DMA base address of the buffer
+ * @len: Buffer length, in bytes
+ *
+ * Falcon uses these buffers for its interrupt status registers and
+ * MAC stats dumps.
+ */
+struct efx_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ unsigned int len;
+};
+
+
+/* Flags for channel->used_flags */
+#define EFX_USED_BY_RX 1
+#define EFX_USED_BY_TX 2
+#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX)
+
+enum efx_rx_alloc_method {
+ RX_ALLOC_METHOD_AUTO = 0,
+ RX_ALLOC_METHOD_SKB = 1,
+ RX_ALLOC_METHOD_PAGE = 2,
+};
+
+/**
+ * struct efx_channel - An Efx channel
+ *
+ * A channel comprises an event queue, at least one TX queue, at least
+ * one RX queue, and an associated tasklet for processing the event
+ * queue.
+ *
+ * @efx: Associated Efx NIC
+ * @evqnum: Event queue number
+ * @channel: Channel instance number
+ * @used_flags: Channel is used by net driver
+ * @enabled: Channel enabled indicator
+ * @irq: IRQ number (MSI and MSI-X only)
+ * @has_interrupt: Channel has an interrupt
+ * @irq_moderation: IRQ moderation value (in us)
+ * @napi_dev: Net device used with NAPI
+ * @napi_str: NAPI control structure
+ * @reset_work: Scheduled reset work thread
+ * @work_pending: Is work pending via NAPI?
+ * @eventq: Event queue buffer
+ * @eventq_read_ptr: Event queue read pointer
+ * @last_eventq_read_ptr: Last event queue read pointer value.
+ * @eventq_magic: Event queue magic value for driver-generated test events
+ * @lro_mgr: LRO state
+ * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
+ * and diagnostic counters
+ * @rx_alloc_push_pages: RX allocation method currently in use for pushing
+ * descriptors
+ * @rx_alloc_pop_pages: RX allocation method currently in use for popping
+ * descriptors
+ * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
+ * @n_rx_ip_frag_err: Count of RX IP fragment errors
+ * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
+ * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
+ * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
+ * @n_rx_overlength: Count of RX_OVERLENGTH errors
+ * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
+ */
+struct efx_channel {
+ struct efx_nic *efx;
+ int evqnum;
+ int channel;
+ int used_flags;
+ int enabled;
+ int irq;
+ unsigned int has_interrupt;
+ unsigned int irq_moderation;
+ struct net_device *napi_dev;
+ struct napi_struct napi_str;
+ struct work_struct reset_work;
+ int work_pending;
+ struct efx_special_buffer eventq;
+ unsigned int eventq_read_ptr;
+ unsigned int last_eventq_read_ptr;
+ unsigned int eventq_magic;
+
+ struct net_lro_mgr lro_mgr;
+ int rx_alloc_level;
+ int rx_alloc_push_pages;
+ int rx_alloc_pop_pages;
+
+ unsigned n_rx_tobe_disc;
+ unsigned n_rx_ip_frag_err;
+ unsigned n_rx_ip_hdr_chksum_err;
+ unsigned n_rx_tcp_udp_chksum_err;
+ unsigned n_rx_frm_trunc;
+ unsigned n_rx_overlength;
+ unsigned n_skbuff_leaks;
+
+ /* Used to pipeline received packets in order to optimise memory
+ * access with prefetches.
+ */
+ struct efx_rx_buffer *rx_pkt;
+ int rx_pkt_csummed;
+
+};
+
+/**
+ * struct efx_blinker - S/W LED blinking context
+ * @led_num: LED ID (board-specific meaning)
+ * @state: Current state - on or off
+ * @resubmit: Timer resubmission flag
+ * @timer: Control timer for blinking
+ */
+struct efx_blinker {
+ int led_num;
+ int state;
+ int resubmit;
+ struct timer_list timer;
+};
+
+
+/**
+ * struct efx_board - board information
+ * @type: Board model type
+ * @major: Major rev. ('A', 'B' ...)
+ * @minor: Minor rev. (0, 1, ...)
+ * @init: Initialisation function
+ * @init_leds: Sets up board LEDs
+ * @set_fault_led: Turns the fault LED on or off
+ * @blink: Starts/stops blinking
+ * @blinker: used to blink LEDs in software
+ */
+struct efx_board {
+ int type;
+ int major;
+ int minor;
+ int (*init) (struct efx_nic *nic);
+ /* As the LEDs are typically attached to the PHY, LEDs
+ * have a separate init callback that happens later than
+ * board init. */
+ int (*init_leds)(struct efx_nic *efx);
+ void (*set_fault_led) (struct efx_nic *efx, int state);
+ void (*blink) (struct efx_nic *efx, int start);
+ struct efx_blinker blinker;
+};
+
+#define STRING_TABLE_LOOKUP(val, member) \
+ member ## _names[val]
+
+enum efx_int_mode {
+ /* Be careful if altering to correct macro below */
+ EFX_INT_MODE_MSIX = 0,
+ EFX_INT_MODE_MSI = 1,
+ EFX_INT_MODE_LEGACY = 2,
+ EFX_INT_MODE_MAX /* Insert any new items before this */
+};
+#define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
+
+enum phy_type {
+ PHY_TYPE_NONE = 0,
+ PHY_TYPE_CX4_RTMR = 1,
+ PHY_TYPE_1G_ALASKA = 2,
+ PHY_TYPE_10XPRESS = 3,
+ PHY_TYPE_XFP = 4,
+ PHY_TYPE_PM8358 = 6,
+ PHY_TYPE_MAX /* Insert any new items before this */
+};
+
+#define PHY_ADDR_INVALID 0xff
+
+enum nic_state {
+ STATE_INIT = 0,
+ STATE_RUNNING = 1,
+ STATE_FINI = 2,
+ STATE_RESETTING = 3, /* rtnl_lock always held */
+ STATE_DISABLED = 4,
+ STATE_MAX,
+};
+
+/*
+ * Alignment of page-allocated RX buffers
+ *
+ * Controls the number of bytes inserted at the start of an RX buffer.
+ * This is the equivalent of NET_IP_ALIGN [which controls the alignment
+ * of the skb->head for hardware DMA].
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define EFX_PAGE_IP_ALIGN 0
+#else
+#define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
+#endif
+
+/*
+ * Alignment of the skb->head which wraps a page-allocated RX buffer
+ *
+ * The skb allocated to wrap an rx_buffer can have this alignment. Since
+ * the data is memcpy'd from the rx_buf, it does not need to be equal to
+ * EFX_PAGE_IP_ALIGN.
+ */
+#define EFX_PAGE_SKB_ALIGN 2
+
+/* Forward declaration */
+struct efx_nic;
+
+/* Pseudo bit-mask flow control field */
+enum efx_fc_type {
+ EFX_FC_RX = 1,
+ EFX_FC_TX = 2,
+ EFX_FC_AUTO = 4,
+};
+
+/**
+ * struct efx_phy_operations - Efx PHY operations table
+ * @init: Initialise PHY
+ * @fini: Shut down PHY
+ * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
+ * @clear_interrupt: Clear down interrupt
+ * @blink: Blink LEDs
+ * @check_hw: Check hardware
+ * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
+ * @mmds: MMD presence mask
+ * @loopbacks: Supported loopback modes mask
+ */
+struct efx_phy_operations {
+ int (*init) (struct efx_nic *efx);
+ void (*fini) (struct efx_nic *efx);
+ void (*reconfigure) (struct efx_nic *efx);
+ void (*clear_interrupt) (struct efx_nic *efx);
+ int (*check_hw) (struct efx_nic *efx);
+ void (*reset_xaui) (struct efx_nic *efx);
+ int mmds;
+ unsigned loopbacks;
+};
+
+/*
+ * Efx extended statistics
+ *
+ * Not all statistics are provided by all supported MACs. The purpose
+ * is this structure is to contain the raw statistics provided by each
+ * MAC.
+ */
+struct efx_mac_stats {
+ u64 tx_bytes;
+ u64 tx_good_bytes;
+ u64 tx_bad_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bad;
+ unsigned long tx_pause;
+ unsigned long tx_control;
+ unsigned long tx_unicast;
+ unsigned long tx_multicast;
+ unsigned long tx_broadcast;
+ unsigned long tx_lt64;
+ unsigned long tx_64;
+ unsigned long tx_65_to_127;
+ unsigned long tx_128_to_255;
+ unsigned long tx_256_to_511;
+ unsigned long tx_512_to_1023;
+ unsigned long tx_1024_to_15xx;
+ unsigned long tx_15xx_to_jumbo;
+ unsigned long tx_gtjumbo;
+ unsigned long tx_collision;
+ unsigned long tx_single_collision;
+ unsigned long tx_multiple_collision;
+ unsigned long tx_excessive_collision;
+ unsigned long tx_deferred;
+ unsigned long tx_late_collision;
+ unsigned long tx_excessive_deferred;
+ unsigned long tx_non_tcpudp;
+ unsigned long tx_mac_src_error;
+ unsigned long tx_ip_src_error;
+ u64 rx_bytes;
+ u64 rx_good_bytes;
+ u64 rx_bad_bytes;
+ unsigned long rx_packets;
+ unsigned long rx_good;
+ unsigned long rx_bad;
+ unsigned long rx_pause;
+ unsigned long rx_control;
+ unsigned long rx_unicast;
+ unsigned long rx_multicast;
+ unsigned long rx_broadcast;
+ unsigned long rx_lt64;
+ unsigned long rx_64;
+ unsigned long rx_65_to_127;
+ unsigned long rx_128_to_255;
+ unsigned long rx_256_to_511;
+ unsigned long rx_512_to_1023;
+ unsigned long rx_1024_to_15xx;
+ unsigned long rx_15xx_to_jumbo;
+ unsigned long rx_gtjumbo;
+ unsigned long rx_bad_lt64;
+ unsigned long rx_bad_64_to_15xx;
+ unsigned long rx_bad_15xx_to_jumbo;
+ unsigned long rx_bad_gtjumbo;
+ unsigned long rx_overflow;
+ unsigned long rx_missed;
+ unsigned long rx_false_carrier;
+ unsigned long rx_symbol_error;
+ unsigned long rx_align_error;
+ unsigned long rx_length_error;
+ unsigned long rx_internal_error;
+ unsigned long rx_good_lt64;
+};
+
+/* Number of bits used in a multicast filter hash address */
+#define EFX_MCAST_HASH_BITS 8
+
+/* Number of (single-bit) entries in a multicast filter hash */
+#define EFX_MCAST_HASH_ENTRIES (1 << EFX_MCAST_HASH_BITS)
+
+/* An Efx multicast filter hash */
+union efx_multicast_hash {
+ u8 byte[EFX_MCAST_HASH_ENTRIES / 8];
+ efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
+};
+
+/**
+ * struct efx_nic - an Efx NIC
+ * @name: Device name (net device name or bus id before net device registered)
+ * @pci_dev: The PCI device
+ * @type: Controller type attributes
+ * @legacy_irq: IRQ number
+ * @workqueue: Workqueue for resets, port reconfigures and the HW monitor
+ * @reset_work: Scheduled reset workitem
+ * @monitor_work: Hardware monitor workitem
+ * @membase_phys: Memory BAR value as physical address
+ * @membase: Memory BAR value
+ * @biu_lock: BIU (bus interface unit) lock
+ * @interrupt_mode: Interrupt mode
+ * @i2c: I2C interface
+ * @board_info: Board-level information
+ * @state: Device state flag. Serialised by the rtnl_lock.
+ * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
+ * @tx_queue: TX DMA queues
+ * @rx_queue: RX DMA queues
+ * @channel: Channels
+ * @rss_queues: Number of RSS queues
+ * @rx_buffer_len: RX buffer length
+ * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @irq_status: Interrupt status buffer
+ * @last_irq_cpu: Last CPU to handle interrupt.
+ * This register is written with the SMP processor ID whenever an
+ * interrupt is handled. It is used by falcon_test_interrupt()
+ * to verify that an interrupt has occurred.
+ * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
+ * @nic_data: Hardware dependant state
+ * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
+ * efx_reconfigure_port()
+ * @port_enabled: Port enabled indicator.
+ * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
+ * efx_reconfigure_work with kernel interfaces. Safe to read under any
+ * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
+ * be held to modify it.
+ * @port_initialized: Port initialized?
+ * @net_dev: Operating system network device. Consider holding the rtnl lock
+ * @rx_checksum_enabled: RX checksumming enabled
+ * @netif_stop_count: Port stop count
+ * @netif_stop_lock: Port stop lock
+ * @mac_stats: MAC statistics. These include all statistics the MACs
+ * can provide. Generic code converts these into a standard
+ * &struct net_device_stats.
+ * @stats_buffer: DMA buffer for statistics
+ * @stats_lock: Statistics update lock
+ * @mac_address: Permanent MAC address
+ * @phy_type: PHY type
+ * @phy_lock: PHY access lock
+ * @phy_op: PHY interface
+ * @phy_data: PHY private data (including PHY-specific stats)
+ * @mii: PHY interface
+ * @tx_disabled: PHY transmitter turned off
+ * @link_up: Link status
+ * @link_options: Link options (MII/GMII format)
+ * @n_link_state_changes: Number of times the link has changed state
+ * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
+ * @multicast_hash: Multicast hash table
+ * @flow_control: Flow control flags - separate RX/TX so can't use link_options
+ * @reconfigure_work: work item for dealing with PHY events
+ * @loopback_mode: Loopback status
+ * @loopback_modes: Supported loopback mode bitmask
+ * @loopback_selftest: Offline self-test private state
+ *
+ * The @priv field of the corresponding &struct net_device points to
+ * this.
+ */
+struct efx_nic {
+ char name[IFNAMSIZ];
+ struct pci_dev *pci_dev;
+ const struct efx_nic_type *type;
+ int legacy_irq;
+ struct workqueue_struct *workqueue;
+ struct work_struct reset_work;
+ struct delayed_work monitor_work;
+ unsigned long membase_phys;
+ void __iomem *membase;
+ spinlock_t biu_lock;
+ enum efx_int_mode interrupt_mode;
+
+ struct efx_i2c_interface i2c;
+ struct efx_board board_info;
+
+ enum nic_state state;
+ enum reset_type reset_pending;
+
+ struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
+ struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
+ struct efx_channel channel[EFX_MAX_CHANNELS];
+
+ int rss_queues;
+ unsigned int rx_buffer_len;
+ unsigned int rx_buffer_order;
+
+ struct efx_buffer irq_status;
+ volatile signed int last_irq_cpu;
+
+ unsigned n_rx_nodesc_drop_cnt;
+
+ void *nic_data;
+
+ struct mutex mac_lock;
+ int port_enabled;
+
+ int port_initialized;
+ struct net_device *net_dev;
+ int rx_checksum_enabled;
+
+ atomic_t netif_stop_count;
+ spinlock_t netif_stop_lock;
+
+ struct efx_mac_stats mac_stats;
+ struct efx_buffer stats_buffer;
+ spinlock_t stats_lock;
+
+ unsigned char mac_address[ETH_ALEN];
+
+ enum phy_type phy_type;
+ spinlock_t phy_lock;
+ struct efx_phy_operations *phy_op;
+ void *phy_data;
+ struct mii_if_info mii;
+ unsigned tx_disabled;
+
+ int link_up;
+ unsigned int link_options;
+ unsigned int n_link_state_changes;
+
+ int promiscuous;
+ union efx_multicast_hash multicast_hash;
+ enum efx_fc_type flow_control;
+ struct work_struct reconfigure_work;
+
+ atomic_t rx_reset;
+ enum efx_loopback_mode loopback_mode;
+ unsigned int loopback_modes;
+
+ void *loopback_selftest;
+};
+
+/**
+ * struct efx_nic_type - Efx device type definition
+ * @mem_bar: Memory BAR number
+ * @mem_map_size: Memory BAR mapped size
+ * @txd_ptr_tbl_base: TX descriptor ring base address
+ * @rxd_ptr_tbl_base: RX descriptor ring base address
+ * @buf_tbl_base: Buffer table base address
+ * @evq_ptr_tbl_base: Event queue pointer table base address
+ * @evq_rptr_tbl_base: Event queue read-pointer table base address
+ * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
+ * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
+ * @evq_size: Event queue size (must be a power of two)
+ * @max_dma_mask: Maximum possible DMA mask
+ * @tx_dma_mask: TX DMA mask
+ * @bug5391_mask: Address mask for bug 5391 workaround
+ * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
+ * @rx_xon_thresh: RX FIFO XON watermark (bytes)
+ * @rx_buffer_padding: Padding added to each RX buffer
+ * @max_interrupt_mode: Highest capability interrupt mode supported
+ * from &enum efx_init_mode.
+ * @phys_addr_channels: Number of channels with physically addressed
+ * descriptors
+ */
+struct efx_nic_type {
+ unsigned int mem_bar;
+ unsigned int mem_map_size;
+ unsigned int txd_ptr_tbl_base;
+ unsigned int rxd_ptr_tbl_base;
+ unsigned int buf_tbl_base;
+ unsigned int evq_ptr_tbl_base;
+ unsigned int evq_rptr_tbl_base;
+
+ unsigned int txd_ring_mask;
+ unsigned int rxd_ring_mask;
+ unsigned int evq_size;
+ dma_addr_t max_dma_mask;
+ unsigned int tx_dma_mask;
+ unsigned bug5391_mask;
+
+ int rx_xoff_thresh;
+ int rx_xon_thresh;
+ unsigned int rx_buffer_padding;
+ unsigned int max_interrupt_mode;
+ unsigned int phys_addr_channels;
+};
+
+/**************************************************************************
+ *
+ * Prototypes and inline functions
+ *
+ *************************************************************************/
+
+/* Iterate over all used channels */
+#define efx_for_each_channel(_channel, _efx) \
+ for (_channel = &_efx->channel[0]; \
+ _channel < &_efx->channel[EFX_MAX_CHANNELS]; \
+ _channel++) \
+ if (!_channel->used_flags) \
+ continue; \
+ else
+
+/* Iterate over all used channels with interrupts */
+#define efx_for_each_channel_with_interrupt(_channel, _efx) \
+ for (_channel = &_efx->channel[0]; \
+ _channel < &_efx->channel[EFX_MAX_CHANNELS]; \
+ _channel++) \
+ if (!(_channel->used_flags && _channel->has_interrupt)) \
+ continue; \
+ else
+
+/* Iterate over all used TX queues */
+#define efx_for_each_tx_queue(_tx_queue, _efx) \
+ for (_tx_queue = &_efx->tx_queue[0]; \
+ _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue++) \
+ if (!_tx_queue->used) \
+ continue; \
+ else
+
+/* Iterate over all TX queues belonging to a channel */
+#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
+ for (_tx_queue = &_channel->efx->tx_queue[0]; \
+ _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue++) \
+ if ((!_tx_queue->used) || \
+ (_tx_queue->channel != _channel)) \
+ continue; \
+ else
+
+/* Iterate over all used RX queues */
+#define efx_for_each_rx_queue(_rx_queue, _efx) \
+ for (_rx_queue = &_efx->rx_queue[0]; \
+ _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES]; \
+ _rx_queue++) \
+ if (!_rx_queue->used) \
+ continue; \
+ else
+
+/* Iterate over all RX queues belonging to a channel */
+#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
+ for (_rx_queue = &_channel->efx->rx_queue[0]; \
+ _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES]; \
+ _rx_queue++) \
+ if ((!_rx_queue->used) || \
+ (_rx_queue->channel != _channel)) \
+ continue; \
+ else
+
+/* Returns a pointer to the specified receive buffer in the RX
+ * descriptor queue.
+ */
+static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
+ unsigned int index)
+{
+ return (&rx_queue->buffer[index]);
+}
+
+/* Set bit in a little-endian bitfield */
+static inline void set_bit_le(int nr, unsigned char *addr)
+{
+ addr[nr / 8] |= (1 << (nr % 8));
+}
+
+/* Clear bit in a little-endian bitfield */
+static inline void clear_bit_le(int nr, unsigned char *addr)
+{
+ addr[nr / 8] &= ~(1 << (nr % 8));
+}
+
+
+/**
+ * EFX_MAX_FRAME_LEN - calculate maximum frame length
+ *
+ * This calculates the maximum frame length that will be used for a
+ * given MTU. The frame length will be equal to the MTU plus a
+ * constant amount of header space and padding. This is the quantity
+ * that the net driver will program into the MAC as the maximum frame
+ * length.
+ *
+ * The 10G MAC used in Falcon requires 8-byte alignment on the frame
+ * length, so we round up to the nearest 8.
+ */
+#define EFX_MAX_FRAME_LEN(mtu) \
+ ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7)
+
+
+#endif /* EFX_NET_DRIVER_H */
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
new file mode 100644
index 000000000000..9d02c84e6b2d
--- /dev/null
+++ b/drivers/net/sfc/phy.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_PHY_H
+#define EFX_PHY_H
+
+/****************************************************************************
+ * 10Xpress (SFX7101) PHY
+ */
+extern struct efx_phy_operations falcon_tenxpress_phy_ops;
+
+enum tenxpress_state {
+ TENXPRESS_STATUS_OFF = 0,
+ TENXPRESS_STATUS_OTEMP = 1,
+ TENXPRESS_STATUS_NORMAL = 2,
+};
+
+extern void tenxpress_set_state(struct efx_nic *efx,
+ enum tenxpress_state state);
+extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
+extern void tenxpress_crc_err(struct efx_nic *efx);
+
+/****************************************************************************
+ * Exported functions from the driver for XFP optical PHYs
+ */
+extern struct efx_phy_operations falcon_xfp_phy_ops;
+
+/* The QUAKE XFP PHY provides various H/W control states for LEDs */
+#define QUAKE_LED_LINK_INVAL (0)
+#define QUAKE_LED_LINK_STAT (1)
+#define QUAKE_LED_LINK_ACT (2)
+#define QUAKE_LED_LINK_ACTSTAT (3)
+#define QUAKE_LED_OFF (4)
+#define QUAKE_LED_ON (5)
+#define QUAKE_LED_LINK_INPUT (6) /* Pin is an input. */
+/* What link the LED tracks */
+#define QUAKE_LED_TXLINK (0)
+#define QUAKE_LED_RXLINK (8)
+
+extern void xfp_set_led(struct efx_nic *p, int led, int state);
+
+#endif
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
new file mode 100644
index 000000000000..670622373ddf
--- /dev/null
+++ b/drivers/net/sfc/rx.c
@@ -0,0 +1,884 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include "net_driver.h"
+#include "rx.h"
+#include "efx.h"
+#include "falcon.h"
+#include "selftest.h"
+#include "workarounds.h"
+
+/* Number of RX descriptors pushed at once. */
+#define EFX_RX_BATCH 8
+
+/* Size of buffer allocated for skb header area. */
+#define EFX_SKB_HEADERS 64u
+
+/*
+ * rx_alloc_method - RX buffer allocation method
+ *
+ * This driver supports two methods for allocating and using RX buffers:
+ * each RX buffer may be backed by an skb or by an order-n page.
+ *
+ * When LRO is in use then the second method has a lower overhead,
+ * since we don't have to allocate then free skbs on reassembled frames.
+ *
+ * Values:
+ * - RX_ALLOC_METHOD_AUTO = 0
+ * - RX_ALLOC_METHOD_SKB = 1
+ * - RX_ALLOC_METHOD_PAGE = 2
+ *
+ * The heuristic for %RX_ALLOC_METHOD_AUTO is a simple hysteresis count
+ * controlled by the parameters below.
+ *
+ * - Since pushing and popping descriptors are separated by the rx_queue
+ * size, so the watermarks should be ~rxd_size.
+ * - The performance win by using page-based allocation for LRO is less
+ * than the performance hit of using page-based allocation of non-LRO,
+ * so the watermarks should reflect this.
+ *
+ * Per channel we maintain a single variable, updated by each channel:
+ *
+ * rx_alloc_level += (lro_performed ? RX_ALLOC_FACTOR_LRO :
+ * RX_ALLOC_FACTOR_SKB)
+ * Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
+ * limits the hysteresis), and update the allocation strategy:
+ *
+ * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
+ * RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
+ */
+static int rx_alloc_method = RX_ALLOC_METHOD_PAGE;
+
+#define RX_ALLOC_LEVEL_LRO 0x2000
+#define RX_ALLOC_LEVEL_MAX 0x3000
+#define RX_ALLOC_FACTOR_LRO 1
+#define RX_ALLOC_FACTOR_SKB (-2)
+
+/* This is the percentage fill level below which new RX descriptors
+ * will be added to the RX descriptor ring.
+ */
+static unsigned int rx_refill_threshold = 90;
+
+/* This is the percentage fill level to which an RX queue will be refilled
+ * when the "RX refill threshold" is reached.
+ */
+static unsigned int rx_refill_limit = 95;
+
+/*
+ * RX maximum head room required.
+ *
+ * This must be at least 1 to prevent overflow and at least 2 to allow
+ * pipelined receives.
+ */
+#define EFX_RXD_HEAD_ROOM 2
+
+/* Macros for zero-order pages (potentially) containing multiple RX buffers */
+#define RX_DATA_OFFSET(_data) \
+ (((unsigned long) (_data)) & (PAGE_SIZE-1))
+#define RX_BUF_OFFSET(_rx_buf) \
+ RX_DATA_OFFSET((_rx_buf)->data)
+
+#define RX_PAGE_SIZE(_efx) \
+ (PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
+
+
+/**************************************************************************
+ *
+ * Linux generic LRO handling
+ *
+ **************************************************************************
+ */
+
+static int efx_lro_get_skb_hdr(struct sk_buff *skb, void **ip_hdr,
+ void **tcpudp_hdr, u64 *hdr_flags, void *priv)
+{
+ struct efx_channel *channel = (struct efx_channel *)priv;
+ struct iphdr *iph;
+ struct tcphdr *th;
+
+ iph = (struct iphdr *)skb->data;
+ if (skb->protocol != htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP)
+ goto fail;
+
+ th = (struct tcphdr *)(skb->data + iph->ihl * 4);
+
+ *tcpudp_hdr = th;
+ *ip_hdr = iph;
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ return 0;
+fail:
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ return -1;
+}
+
+static int efx_get_frag_hdr(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
+ void *priv)
+{
+ struct efx_channel *channel = (struct efx_channel *)priv;
+ struct ethhdr *eh;
+ struct iphdr *iph;
+
+ /* We support EtherII and VLAN encapsulated IPv4 */
+ eh = (struct ethhdr *)(page_address(frag->page) + frag->page_offset);
+ *mac_hdr = eh;
+
+ if (eh->h_proto == htons(ETH_P_IP)) {
+ iph = (struct iphdr *)(eh + 1);
+ } else {
+ struct vlan_ethhdr *veh = (struct vlan_ethhdr *)eh;
+ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+ goto fail;
+
+ iph = (struct iphdr *)(veh + 1);
+ }
+ *ip_hdr = iph;
+
+ /* We can only do LRO over TCP */
+ if (iph->protocol != IPPROTO_TCP)
+ goto fail;
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *tcpudp_hdr = (struct tcphdr *)((u8 *) iph + iph->ihl * 4);
+
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ return 0;
+ fail:
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ return -1;
+}
+
+int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx)
+{
+ size_t s = sizeof(struct net_lro_desc) * EFX_MAX_LRO_DESCRIPTORS;
+ struct net_lro_desc *lro_arr;
+
+ /* Allocate the LRO descriptors structure */
+ lro_arr = kzalloc(s, GFP_KERNEL);
+ if (lro_arr == NULL)
+ return -ENOMEM;
+
+ lro_mgr->lro_arr = lro_arr;
+ lro_mgr->max_desc = EFX_MAX_LRO_DESCRIPTORS;
+ lro_mgr->max_aggr = EFX_MAX_LRO_AGGR;
+ lro_mgr->frag_align_pad = EFX_PAGE_SKB_ALIGN;
+
+ lro_mgr->get_skb_header = efx_lro_get_skb_hdr;
+ lro_mgr->get_frag_header = efx_get_frag_hdr;
+ lro_mgr->dev = efx->net_dev;
+
+ lro_mgr->features = LRO_F_NAPI;
+
+ /* We can pass packets up with the checksum intact */
+ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
+ return 0;
+}
+
+void efx_lro_fini(struct net_lro_mgr *lro_mgr)
+{
+ kfree(lro_mgr->lro_arr);
+ lro_mgr->lro_arr = NULL;
+}
+
+/**
+ * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
+ *
+ * @rx_queue: Efx RX queue
+ * @rx_buf: RX buffer structure to populate
+ *
+ * This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information. Return a negative error code or 0 on success.
+ */
+static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct net_device *net_dev = efx->net_dev;
+ int skb_len = efx->rx_buffer_len;
+
+ rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
+ if (unlikely(!rx_buf->skb))
+ return -ENOMEM;
+
+ /* Adjust the SKB for padding and checksum */
+ skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+ rx_buf->len = skb_len - NET_IP_ALIGN;
+ rx_buf->data = (char *)rx_buf->skb->data;
+ rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_buf->dma_addr = pci_map_single(efx->pci_dev,
+ rx_buf->data, rx_buf->len,
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
+ *
+ * @rx_queue: Efx RX queue
+ * @rx_buf: RX buffer structure to populate
+ *
+ * This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information. Return a negative error code or 0 on success.
+ */
+static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ int bytes, space, offset;
+
+ bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+
+ /* If there is space left in the previously allocated page,
+ * then use it. Otherwise allocate a new one */
+ rx_buf->page = rx_queue->buf_page;
+ if (rx_buf->page == NULL) {
+ dma_addr_t dma_addr;
+
+ rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+ efx->rx_buffer_order);
+ if (unlikely(rx_buf->page == NULL))
+ return -ENOMEM;
+
+ dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
+ 0, RX_PAGE_SIZE(efx),
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(dma_addr))) {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ return -EIO;
+ }
+
+ rx_queue->buf_page = rx_buf->page;
+ rx_queue->buf_dma_addr = dma_addr;
+ rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
+ EFX_PAGE_IP_ALIGN);
+ }
+
+ offset = RX_DATA_OFFSET(rx_queue->buf_data);
+ rx_buf->len = bytes;
+ rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
+ rx_buf->data = rx_queue->buf_data;
+
+ /* Try to pack multiple buffers per page */
+ if (efx->rx_buffer_order == 0) {
+ /* The next buffer starts on the next 512 byte boundary */
+ rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
+ offset += ((bytes + 0x1ff) & ~0x1ff);
+
+ space = RX_PAGE_SIZE(efx) - offset;
+ if (space >= bytes) {
+ /* Refs dropped on kernel releasing each skb */
+ get_page(rx_queue->buf_page);
+ goto out;
+ }
+ }
+
+ /* This is the final RX buffer for this page, so mark it for
+ * unmapping */
+ rx_queue->buf_page = NULL;
+ rx_buf->unmap_addr = rx_queue->buf_dma_addr;
+
+ out:
+ return 0;
+}
+
+/* This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information.
+ */
+static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *new_rx_buf)
+{
+ int rc = 0;
+
+ if (rx_queue->channel->rx_alloc_push_pages) {
+ new_rx_buf->skb = NULL;
+ rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
+ rx_queue->alloc_page_count++;
+ } else {
+ new_rx_buf->page = NULL;
+ rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
+ rx_queue->alloc_skb_count++;
+ }
+
+ if (unlikely(rc < 0))
+ EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
+ rx_queue->queue, rc);
+ return rc;
+}
+
+static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf)
+{
+ if (rx_buf->page) {
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ if (rx_buf->unmap_addr) {
+ pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
+ RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
+ rx_buf->unmap_addr = 0;
+ }
+ } else if (likely(rx_buf->skb)) {
+ pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
+ rx_buf->len, PCI_DMA_FROMDEVICE);
+ }
+}
+
+static inline void efx_free_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf)
+{
+ if (rx_buf->page) {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ } else if (likely(rx_buf->skb)) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ }
+}
+
+static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
+ efx_free_rx_buffer(rx_queue->efx, rx_buf);
+}
+
+/**
+ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
+ * @rx_queue: RX descriptor queue
+ * @retry: Recheck the fill level
+ * This will aim to fill the RX descriptor queue up to
+ * @rx_queue->@fast_fill_limit. If there is insufficient atomic
+ * memory to do so, the caller should retry.
+ */
+static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
+ int retry)
+{
+ struct efx_rx_buffer *rx_buf;
+ unsigned fill_level, index;
+ int i, space, rc = 0;
+
+ /* Calculate current fill level. Do this outside the lock,
+ * because most of the time we'll end up not wanting to do the
+ * fill anyway.
+ */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count);
+ EFX_BUG_ON_PARANOID(fill_level >
+ rx_queue->efx->type->rxd_ring_mask + 1);
+
+ /* Don't fill if we don't need to */
+ if (fill_level >= rx_queue->fast_fill_trigger)
+ return 0;
+
+ /* Record minimum fill level */
+ if (unlikely(fill_level < rx_queue->min_fill))
+ if (fill_level)
+ rx_queue->min_fill = fill_level;
+
+ /* Acquire RX add lock. If this lock is contended, then a fast
+ * fill must already be in progress (e.g. in the refill
+ * tasklet), so we don't need to do anything
+ */
+ if (!spin_trylock_bh(&rx_queue->add_lock))
+ return -1;
+
+ retry:
+ /* Recalculate current fill level now that we have the lock */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count);
+ EFX_BUG_ON_PARANOID(fill_level >
+ rx_queue->efx->type->rxd_ring_mask + 1);
+ space = rx_queue->fast_fill_limit - fill_level;
+ if (space < EFX_RX_BATCH)
+ goto out_unlock;
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
+ " level %d to level %d using %s allocation\n",
+ rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
+ rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
+
+ do {
+ for (i = 0; i < EFX_RX_BATCH; ++i) {
+ index = (rx_queue->added_count &
+ rx_queue->efx->type->rxd_ring_mask);
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ rc = efx_init_rx_buffer(rx_queue, rx_buf);
+ if (unlikely(rc))
+ goto out;
+ ++rx_queue->added_count;
+ }
+ } while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
+ "to level %d\n", rx_queue->queue,
+ rx_queue->added_count - rx_queue->removed_count);
+
+ out:
+ /* Send write pointer to card. */
+ falcon_notify_rx_desc(rx_queue);
+
+ /* If the fast fill is running inside from the refill tasklet, then
+ * for SMP systems it may be running on a different CPU to
+ * RX event processing, which means that the fill level may now be
+ * out of date. */
+ if (unlikely(retry && (rc == 0)))
+ goto retry;
+
+ out_unlock:
+ spin_unlock_bh(&rx_queue->add_lock);
+
+ return rc;
+}
+
+/**
+ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
+ * @rx_queue: RX descriptor queue
+ *
+ * This will aim to fill the RX descriptor queue up to
+ * @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
+ * it will schedule a work item to immediately continue the fast fill
+ */
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
+{
+ int rc;
+
+ rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
+ if (unlikely(rc)) {
+ /* Schedule the work item to run immediately. The hope is
+ * that work is immediately pending to free some memory
+ * (e.g. an RX event or TX completion)
+ */
+ efx_schedule_slow_fill(rx_queue, 0);
+ }
+}
+
+void efx_rx_work(struct work_struct *data)
+{
+ struct efx_rx_queue *rx_queue;
+ int rc;
+
+ rx_queue = container_of(data, struct efx_rx_queue, work.work);
+
+ if (unlikely(!rx_queue->channel->enabled))
+ return;
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
+ "%d\n", rx_queue->queue, raw_smp_processor_id());
+
+ ++rx_queue->slow_fill_count;
+ /* Push new RX descriptors, allowing at least 1 jiffy for
+ * the kernel to free some more memory. */
+ rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
+ if (rc)
+ efx_schedule_slow_fill(rx_queue, 1);
+}
+
+static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf,
+ int len, int *discard,
+ int *leak_packet)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
+
+ if (likely(len <= max_len))
+ return;
+
+ /* The packet must be discarded, but this is only a fatal error
+ * if the caller indicated it was
+ */
+ *discard = 1;
+
+ if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
+ EFX_ERR_RL(efx, " RX queue %d seriously overlength "
+ "RX event (0x%x > 0x%x+0x%x). Leaking\n",
+ rx_queue->queue, len, max_len,
+ efx->type->rx_buffer_padding);
+ /* If this buffer was skb-allocated, then the meta
+ * data at the end of the skb will be trashed. So
+ * we have no choice but to leak the fragment.
+ */
+ *leak_packet = (rx_buf->skb != NULL);
+ efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
+ } else {
+ EFX_ERR_RL(efx, " RX queue %d overlength RX event "
+ "(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
+ }
+
+ rx_queue->channel->n_rx_overlength++;
+}
+
+/* Pass a received packet up through the generic LRO stack
+ *
+ * Handles driverlink veto, and passes the fragment up via
+ * the appropriate LRO method
+ */
+static inline void efx_rx_packet_lro(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct net_lro_mgr *lro_mgr = &channel->lro_mgr;
+ void *priv = channel;
+
+ /* Pass the skb/page into the LRO engine */
+ if (rx_buf->page) {
+ struct skb_frag_struct frags;
+
+ frags.page = rx_buf->page;
+ frags.page_offset = RX_BUF_OFFSET(rx_buf);
+ frags.size = rx_buf->len;
+
+ lro_receive_frags(lro_mgr, &frags, rx_buf->len,
+ rx_buf->len, priv, 0);
+
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ rx_buf->page = NULL;
+ } else {
+ EFX_BUG_ON_PARANOID(!rx_buf->skb);
+
+ lro_receive_skb(lro_mgr, rx_buf->skb, priv);
+ rx_buf->skb = NULL;
+ }
+}
+
+/* Allocate and construct an SKB around a struct page.*/
+static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
+ struct efx_nic *efx,
+ int hdr_len)
+{
+ struct sk_buff *skb;
+
+ /* Allocate an SKB to store the headers */
+ skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
+ if (unlikely(skb == NULL)) {
+ EFX_ERR_RL(efx, "RX out of memory for skb\n");
+ return NULL;
+ }
+
+ EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags);
+ EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
+
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
+
+ skb->len = rx_buf->len;
+ skb->truesize = rx_buf->len + sizeof(struct sk_buff);
+ memcpy(skb->data, rx_buf->data, hdr_len);
+ skb->tail += hdr_len;
+
+ /* Append the remaining page onto the frag list */
+ if (unlikely(rx_buf->len > hdr_len)) {
+ struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
+ frag->page = rx_buf->page;
+ frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
+ frag->size = skb->len - hdr_len;
+ skb_shinfo(skb)->nr_frags = 1;
+ skb->data_len = frag->size;
+ } else {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ skb->data_len = 0;
+ }
+
+ /* Ownership has transferred from the rx_buf to skb */
+ rx_buf->page = NULL;
+
+ /* Move past the ethernet header */
+ skb->protocol = eth_type_trans(skb, efx->net_dev);
+
+ return skb;
+}
+
+void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+ unsigned int len, int checksummed, int discard)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct efx_rx_buffer *rx_buf;
+ int leak_packet = 0;
+
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ EFX_BUG_ON_PARANOID(!rx_buf->data);
+ EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page);
+ EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page));
+
+ /* This allows the refill path to post another buffer.
+ * EFX_RXD_HEAD_ROOM ensures that the slot we are using
+ * isn't overwritten yet.
+ */
+ rx_queue->removed_count++;
+
+ /* Validate the length encoded in the event vs the descriptor pushed */
+ efx_rx_packet__check_len(rx_queue, rx_buf, len,
+ &discard, &leak_packet);
+
+ EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
+ rx_queue->queue, index,
+ (unsigned long long)rx_buf->dma_addr, len,
+ (checksummed ? " [SUMMED]" : ""),
+ (discard ? " [DISCARD]" : ""));
+
+ /* Discard packet, if instructed to do so */
+ if (unlikely(discard)) {
+ if (unlikely(leak_packet))
+ rx_queue->channel->n_skbuff_leaks++;
+ else
+ /* We haven't called efx_unmap_rx_buffer yet,
+ * so fini the entire rx_buffer here */
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ return;
+ }
+
+ /* Release card resources - assumes all RX buffers consumed in-order
+ * per RX queue
+ */
+ efx_unmap_rx_buffer(efx, rx_buf);
+
+ /* Prefetch nice and early so data will (hopefully) be in cache by
+ * the time we look at it.
+ */
+ prefetch(rx_buf->data);
+
+ /* Pipeline receives so that we give time for packet headers to be
+ * prefetched into cache.
+ */
+ rx_buf->len = len;
+ if (rx_queue->channel->rx_pkt)
+ __efx_rx_packet(rx_queue->channel,
+ rx_queue->channel->rx_pkt,
+ rx_queue->channel->rx_pkt_csummed);
+ rx_queue->channel->rx_pkt = rx_buf;
+ rx_queue->channel->rx_pkt_csummed = checksummed;
+}
+
+/* Handle a received packet. Second half: Touches packet payload. */
+void __efx_rx_packet(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf, int checksummed)
+{
+ struct efx_nic *efx = channel->efx;
+ struct sk_buff *skb;
+ int lro = efx->net_dev->features & NETIF_F_LRO;
+
+ /* If we're in loopback test, then pass the packet directly to the
+ * loopback layer, and free the rx_buf here
+ */
+ if (unlikely(efx->loopback_selftest)) {
+ efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
+ efx_free_rx_buffer(efx, rx_buf);
+ goto done;
+ }
+
+ if (rx_buf->skb) {
+ prefetch(skb_shinfo(rx_buf->skb));
+
+ skb_put(rx_buf->skb, rx_buf->len);
+
+ /* Move past the ethernet header. rx_buf->data still points
+ * at the ethernet header */
+ rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
+ efx->net_dev);
+ }
+
+ /* Both our generic-LRO and SFC-SSR support skb and page based
+ * allocation, but neither support switching from one to the
+ * other on the fly. If we spot that the allocation mode has
+ * changed, then flush the LRO state.
+ */
+ if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
+ efx_flush_lro(channel);
+ channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
+ }
+ if (likely(checksummed && lro)) {
+ efx_rx_packet_lro(channel, rx_buf);
+ goto done;
+ }
+
+ /* Form an skb if required */
+ if (rx_buf->page) {
+ int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
+ skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
+ if (unlikely(skb == NULL)) {
+ efx_free_rx_buffer(efx, rx_buf);
+ goto done;
+ }
+ } else {
+ /* We now own the SKB */
+ skb = rx_buf->skb;
+ rx_buf->skb = NULL;
+ }
+
+ EFX_BUG_ON_PARANOID(rx_buf->page);
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ EFX_BUG_ON_PARANOID(!skb);
+
+ /* Set the SKB flags */
+ if (unlikely(!checksummed || !efx->rx_checksum_enabled))
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Pass the packet up */
+ netif_receive_skb(skb);
+
+ /* Update allocation strategy method */
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+
+done:
+ efx->net_dev->last_rx = jiffies;
+}
+
+void efx_rx_strategy(struct efx_channel *channel)
+{
+ enum efx_rx_alloc_method method = rx_alloc_method;
+
+ /* Only makes sense to use page based allocation if LRO is enabled */
+ if (!(channel->efx->net_dev->features & NETIF_F_LRO)) {
+ method = RX_ALLOC_METHOD_SKB;
+ } else if (method == RX_ALLOC_METHOD_AUTO) {
+ /* Constrain the rx_alloc_level */
+ if (channel->rx_alloc_level < 0)
+ channel->rx_alloc_level = 0;
+ else if (channel->rx_alloc_level > RX_ALLOC_LEVEL_MAX)
+ channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
+
+ /* Decide on the allocation method */
+ method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_LRO) ?
+ RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
+ }
+
+ /* Push the option */
+ channel->rx_alloc_push_pages = (method == RX_ALLOC_METHOD_PAGE);
+}
+
+int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int rxq_size;
+ int rc;
+
+ EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
+
+ /* Allocate RX buffers */
+ rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
+ rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
+ if (!rx_queue->buffer) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ rc = falcon_probe_rx(rx_queue);
+ if (rc)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ kfree(rx_queue->buffer);
+ rx_queue->buffer = NULL;
+ fail1:
+ rx_queue->used = 0;
+
+ return rc;
+}
+
+int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int max_fill, trigger, limit;
+
+ EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
+
+ /* Initialise ptr fields */
+ rx_queue->added_count = 0;
+ rx_queue->notified_count = 0;
+ rx_queue->removed_count = 0;
+ rx_queue->min_fill = -1U;
+ rx_queue->min_overfill = -1U;
+
+ /* Initialise limit fields */
+ max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
+ trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
+ limit = max_fill * min(rx_refill_limit, 100U) / 100U;
+
+ rx_queue->max_fill = max_fill;
+ rx_queue->fast_fill_trigger = trigger;
+ rx_queue->fast_fill_limit = limit;
+
+ /* Set up RX descriptor ring */
+ return falcon_init_rx(rx_queue);
+}
+
+void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ int i;
+ struct efx_rx_buffer *rx_buf;
+
+ EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+
+ falcon_fini_rx(rx_queue);
+
+ /* Release RX buffers NB start at index 0 not current HW ptr */
+ if (rx_queue->buffer) {
+ for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
+ rx_buf = efx_rx_buffer(rx_queue, i);
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ }
+ }
+
+ /* For a page that is part-way through splitting into RX buffers */
+ if (rx_queue->buf_page != NULL) {
+ pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
+ RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
+ __free_pages(rx_queue->buf_page,
+ rx_queue->efx->rx_buffer_order);
+ rx_queue->buf_page = NULL;
+ }
+}
+
+void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
+
+ falcon_remove_rx(rx_queue);
+
+ kfree(rx_queue->buffer);
+ rx_queue->buffer = NULL;
+ rx_queue->used = 0;
+}
+
+void efx_flush_lro(struct efx_channel *channel)
+{
+ lro_flush_all(&channel->lro_mgr);
+}
+
+
+module_param(rx_alloc_method, int, 0644);
+MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
+
+module_param(rx_refill_threshold, uint, 0444);
+MODULE_PARM_DESC(rx_refill_threshold,
+ "RX descriptor ring fast/slow fill threshold (%)");
+
diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h
new file mode 100644
index 000000000000..f35e377bfc5f
--- /dev/null
+++ b/drivers/net/sfc/rx.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_RX_H
+#define EFX_RX_H
+
+#include "net_driver.h"
+
+int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
+int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
+
+int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx);
+void efx_lro_fini(struct net_lro_mgr *lro_mgr);
+void efx_flush_lro(struct efx_channel *channel);
+void efx_rx_strategy(struct efx_channel *channel);
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
+void efx_rx_work(struct work_struct *data);
+void __efx_rx_packet(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf, int checksummed);
+
+#endif /* EFX_RX_H */
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
new file mode 100644
index 000000000000..cbda15946e8f
--- /dev/null
+++ b/drivers/net/sfc/selftest.c
@@ -0,0 +1,717 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel_stat.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/udp.h>
+#include <linux/rtnetlink.h>
+#include <asm/io.h>
+#include "net_driver.h"
+#include "ethtool.h"
+#include "efx.h"
+#include "falcon.h"
+#include "selftest.h"
+#include "boards.h"
+#include "workarounds.h"
+#include "mac.h"
+
+/*
+ * Loopback test packet structure
+ *
+ * The self-test should stress every RSS vector, and unfortunately
+ * Falcon only performs RSS on TCP/UDP packets.
+ */
+struct efx_loopback_payload {
+ struct ethhdr header;
+ struct iphdr ip;
+ struct udphdr udp;
+ __be16 iteration;
+ const char msg[64];
+} __attribute__ ((packed));
+
+/* Loopback test source MAC address */
+static const unsigned char payload_source[ETH_ALEN] = {
+ 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
+};
+
+static const char *payload_msg =
+ "Hello world! This is an Efx loopback test in progress!";
+
+/**
+ * efx_selftest_state - persistent state during a selftest
+ * @flush: Drop all packets in efx_loopback_rx_packet
+ * @packet_count: Number of packets being used in this test
+ * @skbs: An array of skbs transmitted
+ * @rx_good: RX good packet count
+ * @rx_bad: RX bad packet count
+ * @payload: Payload used in tests
+ */
+struct efx_selftest_state {
+ int flush;
+ int packet_count;
+ struct sk_buff **skbs;
+ atomic_t rx_good;
+ atomic_t rx_bad;
+ struct efx_loopback_payload payload;
+};
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ **************************************************************************/
+
+/* Level of loopback testing
+ *
+ * The maximum packet burst length is 16**(n-1), i.e.
+ *
+ * - Level 0 : no packets
+ * - Level 1 : 1 packet
+ * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets)
+ * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets)
+ *
+ */
+static unsigned int loopback_test_level = 3;
+
+/**************************************************************************
+ *
+ * Interrupt and event queue testing
+ *
+ **************************************************************************/
+
+/* Test generation and receipt of interrupts */
+static int efx_test_interrupts(struct efx_nic *efx,
+ struct efx_self_tests *tests)
+{
+ struct efx_channel *channel;
+
+ EFX_LOG(efx, "testing interrupts\n");
+ tests->interrupt = -1;
+
+ /* Reset interrupt flag */
+ efx->last_irq_cpu = -1;
+ smp_wmb();
+
+ /* ACK each interrupting event queue. Receiving an interrupt due to
+ * traffic before a test event is raised is considered a pass */
+ efx_for_each_channel_with_interrupt(channel, efx) {
+ if (channel->work_pending)
+ efx_process_channel_now(channel);
+ if (efx->last_irq_cpu >= 0)
+ goto success;
+ }
+
+ falcon_generate_interrupt(efx);
+
+ /* Wait for arrival of test interrupt. */
+ EFX_LOG(efx, "waiting for test interrupt\n");
+ schedule_timeout_uninterruptible(HZ / 10);
+ if (efx->last_irq_cpu >= 0)
+ goto success;
+
+ EFX_ERR(efx, "timed out waiting for interrupt\n");
+ return -ETIMEDOUT;
+
+ success:
+ EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n",
+ efx->interrupt_mode, efx->last_irq_cpu);
+ tests->interrupt = 1;
+ return 0;
+}
+
+/* Test generation and receipt of non-interrupting events */
+static int efx_test_eventq(struct efx_channel *channel,
+ struct efx_self_tests *tests)
+{
+ unsigned int magic;
+
+ /* Channel specific code, limited to 20 bits */
+ magic = (0x00010150 + channel->channel);
+ EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
+ channel->channel, magic);
+
+ tests->eventq_dma[channel->channel] = -1;
+ tests->eventq_int[channel->channel] = 1; /* fake pass */
+ tests->eventq_poll[channel->channel] = 1; /* fake pass */
+
+ /* Reset flag and zero magic word */
+ channel->efx->last_irq_cpu = -1;
+ channel->eventq_magic = 0;
+ smp_wmb();
+
+ falcon_generate_test_event(channel, magic);
+ udelay(1);
+
+ efx_process_channel_now(channel);
+ if (channel->eventq_magic != magic) {
+ EFX_ERR(channel->efx, "channel %d failed to see test event\n",
+ channel->channel);
+ return -ETIMEDOUT;
+ } else {
+ tests->eventq_dma[channel->channel] = 1;
+ }
+
+ return 0;
+}
+
+/* Test generation and receipt of interrupting events */
+static int efx_test_eventq_irq(struct efx_channel *channel,
+ struct efx_self_tests *tests)
+{
+ unsigned int magic, count;
+
+ /* Channel specific code, limited to 20 bits */
+ magic = (0x00010150 + channel->channel);
+ EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
+ channel->channel, magic);
+
+ tests->eventq_dma[channel->channel] = -1;
+ tests->eventq_int[channel->channel] = -1;
+ tests->eventq_poll[channel->channel] = -1;
+
+ /* Reset flag and zero magic word */
+ channel->efx->last_irq_cpu = -1;
+ channel->eventq_magic = 0;
+ smp_wmb();
+
+ falcon_generate_test_event(channel, magic);
+
+ /* Wait for arrival of interrupt */
+ count = 0;
+ do {
+ schedule_timeout_uninterruptible(HZ / 100);
+
+ if (channel->work_pending)
+ efx_process_channel_now(channel);
+
+ if (channel->eventq_magic == magic)
+ goto eventq_ok;
+ } while (++count < 2);
+
+ EFX_ERR(channel->efx, "channel %d timed out waiting for event queue\n",
+ channel->channel);
+
+ /* See if interrupt arrived */
+ if (channel->efx->last_irq_cpu >= 0) {
+ EFX_ERR(channel->efx, "channel %d saw interrupt on CPU%d "
+ "during event queue test\n", channel->channel,
+ raw_smp_processor_id());
+ tests->eventq_int[channel->channel] = 1;
+ }
+
+ /* Check to see if event was received even if interrupt wasn't */
+ efx_process_channel_now(channel);
+ if (channel->eventq_magic == magic) {
+ EFX_ERR(channel->efx, "channel %d event was generated, but "
+ "failed to trigger an interrupt\n", channel->channel);
+ tests->eventq_dma[channel->channel] = 1;
+ }
+
+ return -ETIMEDOUT;
+ eventq_ok:
+ EFX_LOG(channel->efx, "channel %d event queue passed\n",
+ channel->channel);
+ tests->eventq_dma[channel->channel] = 1;
+ tests->eventq_int[channel->channel] = 1;
+ tests->eventq_poll[channel->channel] = 1;
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * PHY testing
+ *
+ **************************************************************************/
+
+/* Check PHY presence by reading the PHY ID registers */
+static int efx_test_phy(struct efx_nic *efx,
+ struct efx_self_tests *tests)
+{
+ u16 physid1, physid2;
+ struct mii_if_info *mii = &efx->mii;
+ struct net_device *net_dev = efx->net_dev;
+
+ if (efx->phy_type == PHY_TYPE_NONE)
+ return 0;
+
+ EFX_LOG(efx, "testing PHY presence\n");
+ tests->phy_ok = -1;
+
+ physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
+ physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
+
+ if ((physid1 != 0x0000) && (physid1 != 0xffff) &&
+ (physid2 != 0x0000) && (physid2 != 0xffff)) {
+ EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n",
+ mii->phy_id, physid1, physid2);
+ tests->phy_ok = 1;
+ return 0;
+ }
+
+ EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id);
+ return -ENODEV;
+}
+
+/**************************************************************************
+ *
+ * Loopback testing
+ * NB Only one loopback test can be executing concurrently.
+ *
+ **************************************************************************/
+
+/* Loopback test RX callback
+ * This is called for each received packet during loopback testing.
+ */
+void efx_loopback_rx_packet(struct efx_nic *efx,
+ const char *buf_ptr, int pkt_len)
+{
+ struct efx_selftest_state *state = efx->loopback_selftest;
+ struct efx_loopback_payload *received;
+ struct efx_loopback_payload *payload;
+
+ BUG_ON(!buf_ptr);
+
+ /* If we are just flushing, then drop the packet */
+ if ((state == NULL) || state->flush)
+ return;
+
+ payload = &state->payload;
+
+ received = (struct efx_loopback_payload *)(char *) buf_ptr;
+ received->ip.saddr = payload->ip.saddr;
+ received->ip.check = payload->ip.check;
+
+ /* Check that header exists */
+ if (pkt_len < sizeof(received->header)) {
+ EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
+ "test\n", pkt_len, LOOPBACK_MODE(efx));
+ goto err;
+ }
+
+ /* Check that the ethernet header exists */
+ if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) {
+ EFX_ERR(efx, "saw non-loopback RX packet in %s loopback test\n",
+ LOOPBACK_MODE(efx));
+ goto err;
+ }
+
+ /* Check packet length */
+ if (pkt_len != sizeof(*payload)) {
+ EFX_ERR(efx, "saw incorrect RX packet length %d (wanted %d) in "
+ "%s loopback test\n", pkt_len, (int)sizeof(*payload),
+ LOOPBACK_MODE(efx));
+ goto err;
+ }
+
+ /* Check that IP header matches */
+ if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) {
+ EFX_ERR(efx, "saw corrupted IP header in %s loopback test\n",
+ LOOPBACK_MODE(efx));
+ goto err;
+ }
+
+ /* Check that msg and padding matches */
+ if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) {
+ EFX_ERR(efx, "saw corrupted RX packet in %s loopback test\n",
+ LOOPBACK_MODE(efx));
+ goto err;
+ }
+
+ /* Check that iteration matches */
+ if (received->iteration != payload->iteration) {
+ EFX_ERR(efx, "saw RX packet from iteration %d (wanted %d) in "
+ "%s loopback test\n", ntohs(received->iteration),
+ ntohs(payload->iteration), LOOPBACK_MODE(efx));
+ goto err;
+ }
+
+ /* Increase correct RX count */
+ EFX_TRACE(efx, "got loopback RX in %s loopback test\n",
+ LOOPBACK_MODE(efx));
+
+ atomic_inc(&state->rx_good);
+ return;
+
+ err:
+#ifdef EFX_ENABLE_DEBUG
+ if (atomic_read(&state->rx_bad) == 0) {
+ EFX_ERR(efx, "received packet:\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
+ buf_ptr, pkt_len, 0);
+ EFX_ERR(efx, "expected packet:\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
+ &state->payload, sizeof(state->payload), 0);
+ }
+#endif
+ atomic_inc(&state->rx_bad);
+}
+
+/* Initialise an efx_selftest_state for a new iteration */
+static void efx_iterate_state(struct efx_nic *efx)
+{
+ struct efx_selftest_state *state = efx->loopback_selftest;
+ struct net_device *net_dev = efx->net_dev;
+ struct efx_loopback_payload *payload = &state->payload;
+
+ /* Initialise the layerII header */
+ memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN);
+ memcpy(&payload->header.h_source, &payload_source, ETH_ALEN);
+ payload->header.h_proto = htons(ETH_P_IP);
+
+ /* saddr set later and used as incrementing count */
+ payload->ip.daddr = htonl(INADDR_LOOPBACK);
+ payload->ip.ihl = 5;
+ payload->ip.check = htons(0xdead);
+ payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr));
+ payload->ip.version = IPVERSION;
+ payload->ip.protocol = IPPROTO_UDP;
+
+ /* Initialise udp header */
+ payload->udp.source = 0;
+ payload->udp.len = htons(sizeof(*payload) - sizeof(struct ethhdr) -
+ sizeof(struct iphdr));
+ payload->udp.check = 0; /* checksum ignored */
+
+ /* Fill out payload */
+ payload->iteration = htons(ntohs(payload->iteration) + 1);
+ memcpy(&payload->msg, payload_msg, sizeof(payload_msg));
+
+ /* Fill out remaining state members */
+ atomic_set(&state->rx_good, 0);
+ atomic_set(&state->rx_bad, 0);
+ smp_wmb();
+}
+
+static int efx_tx_loopback(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct efx_selftest_state *state = efx->loopback_selftest;
+ struct efx_loopback_payload *payload;
+ struct sk_buff *skb;
+ int i, rc;
+
+ /* Transmit N copies of buffer */
+ for (i = 0; i < state->packet_count; i++) {
+ /* Allocate an skb, holding an extra reference for
+ * transmit completion counting */
+ skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ state->skbs[i] = skb;
+ skb_get(skb);
+
+ /* Copy the payload in, incrementing the source address to
+ * exercise the rss vectors */
+ payload = ((struct efx_loopback_payload *)
+ skb_put(skb, sizeof(state->payload)));
+ memcpy(payload, &state->payload, sizeof(state->payload));
+ payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2));
+
+ /* Ensure everything we've written is visible to the
+ * interrupt handler. */
+ smp_wmb();
+
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_lock_bh(efx->net_dev);
+ rc = efx_xmit(efx, tx_queue, skb);
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_unlock_bh(efx->net_dev);
+
+ if (rc != NETDEV_TX_OK) {
+ EFX_ERR(efx, "TX queue %d could not transmit packet %d "
+ "of %d in %s loopback test\n", tx_queue->queue,
+ i + 1, state->packet_count, LOOPBACK_MODE(efx));
+
+ /* Defer cleaning up the other skbs for the caller */
+ kfree_skb(skb);
+ return -EPIPE;
+ }
+ }
+
+ return 0;
+}
+
+static int efx_rx_loopback(struct efx_tx_queue *tx_queue,
+ struct efx_loopback_self_tests *lb_tests)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct efx_selftest_state *state = efx->loopback_selftest;
+ struct sk_buff *skb;
+ int tx_done = 0, rx_good, rx_bad;
+ int i, rc = 0;
+
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_lock_bh(efx->net_dev);
+
+ /* Count the number of tx completions, and decrement the refcnt. Any
+ * skbs not already completed will be free'd when the queue is flushed */
+ for (i=0; i < state->packet_count; i++) {
+ skb = state->skbs[i];
+ if (skb && !skb_shared(skb))
+ ++tx_done;
+ dev_kfree_skb_any(skb);
+ }
+
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_unlock_bh(efx->net_dev);
+
+ /* Check TX completion and received packet counts */
+ rx_good = atomic_read(&state->rx_good);
+ rx_bad = atomic_read(&state->rx_bad);
+ if (tx_done != state->packet_count) {
+ /* Don't free the skbs; they will be picked up on TX
+ * overflow or channel teardown.
+ */
+ EFX_ERR(efx, "TX queue %d saw only %d out of an expected %d "
+ "TX completion events in %s loopback test\n",
+ tx_queue->queue, tx_done, state->packet_count,
+ LOOPBACK_MODE(efx));
+ rc = -ETIMEDOUT;
+ /* Allow to fall through so we see the RX errors as well */
+ }
+
+ /* We may always be up to a flush away from our desired packet total */
+ if (rx_good != state->packet_count) {
+ EFX_LOG(efx, "TX queue %d saw only %d out of an expected %d "
+ "received packets in %s loopback test\n",
+ tx_queue->queue, rx_good, state->packet_count,
+ LOOPBACK_MODE(efx));
+ rc = -ETIMEDOUT;
+ /* Fall through */
+ }
+
+ /* Update loopback test structure */
+ lb_tests->tx_sent[tx_queue->queue] += state->packet_count;
+ lb_tests->tx_done[tx_queue->queue] += tx_done;
+ lb_tests->rx_good += rx_good;
+ lb_tests->rx_bad += rx_bad;
+
+ return rc;
+}
+
+static int
+efx_test_loopback(struct efx_tx_queue *tx_queue,
+ struct efx_loopback_self_tests *lb_tests)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct efx_selftest_state *state = efx->loopback_selftest;
+ struct efx_channel *channel;
+ int i, rc = 0;
+
+ for (i = 0; i < loopback_test_level; i++) {
+ /* Determine how many packets to send */
+ state->packet_count = (efx->type->txd_ring_mask + 1) / 3;
+ state->packet_count = min(1 << (i << 2), state->packet_count);
+ state->skbs = kzalloc(sizeof(state->skbs[0]) *
+ state->packet_count, GFP_KERNEL);
+ state->flush = 0;
+
+ EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
+ "packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+ state->packet_count);
+
+ efx_iterate_state(efx);
+ rc = efx_tx_loopback(tx_queue);
+
+ /* NAPI polling is not enabled, so process channels synchronously */
+ schedule_timeout_uninterruptible(HZ / 50);
+ efx_for_each_channel_with_interrupt(channel, efx) {
+ if (channel->work_pending)
+ efx_process_channel_now(channel);
+ }
+
+ rc |= efx_rx_loopback(tx_queue, lb_tests);
+ kfree(state->skbs);
+
+ if (rc) {
+ /* Wait a while to ensure there are no packets
+ * floating around after a failure. */
+ schedule_timeout_uninterruptible(HZ / 10);
+ return rc;
+ }
+ }
+
+ EFX_LOG(efx, "TX queue %d passed %s loopback test with a burst length "
+ "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+ state->packet_count);
+
+ return rc;
+}
+
+static int efx_test_loopbacks(struct efx_nic *efx,
+ struct efx_self_tests *tests,
+ unsigned int loopback_modes)
+{
+ struct efx_selftest_state *state = efx->loopback_selftest;
+ struct ethtool_cmd ecmd, ecmd_loopback;
+ struct efx_tx_queue *tx_queue;
+ enum efx_loopback_mode old_mode, mode;
+ int count, rc = 0, link_up;
+
+ rc = efx_ethtool_get_settings(efx->net_dev, &ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not get GMII settings\n");
+ return rc;
+ }
+ old_mode = efx->loopback_mode;
+
+ /* Disable autonegotiation for the purposes of loopback */
+ memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback));
+ if (ecmd_loopback.autoneg == AUTONEG_ENABLE) {
+ ecmd_loopback.autoneg = AUTONEG_DISABLE;
+ ecmd_loopback.duplex = DUPLEX_FULL;
+ ecmd_loopback.speed = SPEED_10000;
+ }
+
+ rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback);
+ if (rc) {
+ EFX_ERR(efx, "could not disable autonegotiation\n");
+ goto out;
+ }
+ tests->loopback_speed = ecmd_loopback.speed;
+ tests->loopback_full_duplex = ecmd_loopback.duplex;
+
+ /* Test all supported loopback modes */
+ for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+ if (!(loopback_modes & (1 << mode)))
+ continue;
+
+ /* Move the port into the specified loopback mode. */
+ state->flush = 1;
+ efx->loopback_mode = mode;
+ efx_reconfigure_port(efx);
+
+ /* Wait for the PHY to signal the link is up */
+ count = 0;
+ do {
+ struct efx_channel *channel = &efx->channel[0];
+
+ falcon_check_xmac(efx);
+ schedule_timeout_uninterruptible(HZ / 10);
+ if (channel->work_pending)
+ efx_process_channel_now(channel);
+ /* Wait for PHY events to be processed */
+ flush_workqueue(efx->workqueue);
+ rmb();
+
+ /* efx->link_up can be 1 even if the XAUI link is down,
+ * (bug5762). Usually, it's not worth bothering with the
+ * difference, but for selftests, we need that extra
+ * guarantee that the link is really, really, up.
+ */
+ link_up = efx->link_up;
+ if (!falcon_xaui_link_ok(efx))
+ link_up = 0;
+
+ } while ((++count < 20) && !link_up);
+
+ /* The link should now be up. If it isn't, there is no point
+ * in attempting a loopback test */
+ if (!link_up) {
+ EFX_ERR(efx, "loopback %s never came up\n",
+ LOOPBACK_MODE(efx));
+ rc = -EIO;
+ goto out;
+ }
+
+ EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
+ LOOPBACK_MODE(efx), count);
+
+ /* Test every TX queue */
+ efx_for_each_tx_queue(tx_queue, efx) {
+ rc |= efx_test_loopback(tx_queue,
+ &tests->loopback[mode]);
+ if (rc)
+ goto out;
+ }
+ }
+
+ out:
+ /* Take out of loopback and restore PHY settings */
+ state->flush = 1;
+ efx->loopback_mode = old_mode;
+ efx_ethtool_set_settings(efx->net_dev, &ecmd);
+
+ return rc;
+}
+
+/**************************************************************************
+ *
+ * Entry points
+ *
+ *************************************************************************/
+
+/* Online (i.e. non-disruptive) testing
+ * This checks interrupt generation, event delivery and PHY presence. */
+int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+ struct efx_channel *channel;
+ int rc = 0;
+
+ EFX_LOG(efx, "performing online self-tests\n");
+
+ rc |= efx_test_interrupts(efx, tests);
+ efx_for_each_channel(channel, efx) {
+ if (channel->has_interrupt)
+ rc |= efx_test_eventq_irq(channel, tests);
+ else
+ rc |= efx_test_eventq(channel, tests);
+ }
+ rc |= efx_test_phy(efx, tests);
+
+ if (rc)
+ EFX_ERR(efx, "failed online self-tests\n");
+
+ return rc;
+}
+
+/* Offline (i.e. disruptive) testing
+ * This checks MAC and PHY loopback on the specified port. */
+int efx_offline_test(struct efx_nic *efx,
+ struct efx_self_tests *tests, unsigned int loopback_modes)
+{
+ struct efx_selftest_state *state;
+ int rc = 0;
+
+ EFX_LOG(efx, "performing offline self-tests\n");
+
+ /* Create a selftest_state structure to hold state for the test */
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Set the port loopback_selftest member. From this point on
+ * all received packets will be dropped. Mark the state as
+ * "flushing" so all inflight packets are dropped */
+ BUG_ON(efx->loopback_selftest);
+ state->flush = 1;
+ efx->loopback_selftest = (void *)state;
+
+ rc = efx_test_loopbacks(efx, tests, loopback_modes);
+
+ efx->loopback_selftest = NULL;
+ wmb();
+ kfree(state);
+
+ out:
+ if (rc)
+ EFX_ERR(efx, "failed offline self-tests\n");
+
+ return rc;
+}
+
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h
new file mode 100644
index 000000000000..f6999c2b622d
--- /dev/null
+++ b/drivers/net/sfc/selftest.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_SELFTEST_H
+#define EFX_SELFTEST_H
+
+#include "net_driver.h"
+
+/*
+ * Self tests
+ */
+
+struct efx_loopback_self_tests {
+ int tx_sent[EFX_MAX_TX_QUEUES];
+ int tx_done[EFX_MAX_TX_QUEUES];
+ int rx_good;
+ int rx_bad;
+};
+
+/* Efx self test results
+ * For fields which are not counters, 1 indicates success and -1
+ * indicates failure.
+ */
+struct efx_self_tests {
+ int interrupt;
+ int eventq_dma[EFX_MAX_CHANNELS];
+ int eventq_int[EFX_MAX_CHANNELS];
+ int eventq_poll[EFX_MAX_CHANNELS];
+ int phy_ok;
+ int loopback_speed;
+ int loopback_full_duplex;
+ struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX];
+};
+
+extern void efx_loopback_rx_packet(struct efx_nic *efx,
+ const char *buf_ptr, int pkt_len);
+extern int efx_online_test(struct efx_nic *efx,
+ struct efx_self_tests *tests);
+extern int efx_offline_test(struct efx_nic *efx,
+ struct efx_self_tests *tests,
+ unsigned int loopback_modes);
+
+#endif /* EFX_SELFTEST_H */
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
new file mode 100644
index 000000000000..725d1a539c49
--- /dev/null
+++ b/drivers/net/sfc/sfe4001.c
@@ -0,0 +1,266 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+/*****************************************************************************
+ * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
+ * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
+ * the PHY
+ */
+#include <linux/delay.h>
+#include "efx.h"
+#include "phy.h"
+#include "boards.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "mac.h"
+
+/**************************************************************************
+ *
+ * I2C IO Expander device
+ *
+ **************************************************************************/
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_INVERT 0x04
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_SHORTEN_JTAG_LBN 5
+#define P0_SHORTEN_JTAG_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+#define P0_DSP_RESET_LBN 7
+#define P0_DSP_RESET_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_OUT 0x03
+#define P1_INVERT 0x05
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_RESERVED_LBN 2
+#define P1_RESERVED_WIDTH 2
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+
+/**************************************************************************
+ *
+ * Temperature Sensor
+ *
+ **************************************************************************/
+#define MAX6647 0x4e
+
+#define RLTS 0x00
+#define RLTE 0x01
+#define RSL 0x02
+#define RCL 0x03
+#define RCRA 0x04
+#define RLHN 0x05
+#define RLLI 0x06
+#define RRHI 0x07
+#define RRLS 0x08
+#define WCRW 0x0a
+#define WLHO 0x0b
+#define WRHA 0x0c
+#define WRLN 0x0e
+#define OSHT 0x0f
+#define REET 0x10
+#define RIET 0x11
+#define RWOE 0x19
+#define RWOI 0x20
+#define HYS 0x21
+#define QUEUE 0x22
+#define MFID 0xfe
+#define REVID 0xff
+
+/* Status bits */
+#define MAX6647_BUSY (1 << 7) /* ADC is converting */
+#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
+#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
+#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
+#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
+#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
+#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
+#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
+
+static const u8 xgphy_max_temperature = 90;
+
+void sfe4001_poweroff(struct efx_nic *efx)
+{
+ struct efx_i2c_interface *i2c = &efx->i2c;
+
+ u8 cfg, out, in;
+
+ EFX_INFO(efx, "%s\n", __func__);
+
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+
+ /* Disable port 1 outputs on IO expander */
+ cfg = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+
+ /* Disable port 0 outputs on IO expander */
+ cfg = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+
+ /* Clear any over-temperature alert */
+ (void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+}
+
+/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
+ * to the FLASH_CFG_1 input on the DSP. We must keep it high at power-
+ * up to allow writing the flash (done through MDIO from userland).
+ */
+unsigned int sfe4001_phy_flash_cfg;
+module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444);
+MODULE_PARM_DESC(phy_flash_cfg,
+ "Force PHY to enter flash configuration mode");
+
+/* This board uses an I2C expander to provider power to the PHY, which needs to
+ * be turned on before the PHY can be used.
+ * Context: Process context, rtnl lock held
+ */
+int sfe4001_poweron(struct efx_nic *efx)
+{
+ struct efx_i2c_interface *i2c = &efx->i2c;
+ unsigned int count;
+ int rc;
+ u8 out, in, cfg;
+ efx_dword_t reg;
+
+ /* 10Xpress has fixed-function LED pins, so there is no board-specific
+ * blink code. */
+ efx->board_info.blink = tenxpress_phy_blink;
+
+ /* Ensure that XGXS and XAUI SerDes are held in reset */
+ EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
+ XX_PWRDNB_EN, 1,
+ XX_RSTPLLAB_EN, 1,
+ XX_RESETA_EN, 1,
+ XX_RESETB_EN, 1,
+ XX_RSTXGXSRX_EN, 1,
+ XX_RSTXGXSTX_EN, 1);
+ falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Set DSP over-temperature alert threshold */
+ EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
+ rc = efx_i2c_write(i2c, MAX6647, WLHO,
+ &xgphy_max_temperature, 1);
+ if (rc)
+ goto fail1;
+
+ /* Read it back and verify */
+ rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
+ if (rc)
+ goto fail1;
+ if (in != xgphy_max_temperature) {
+ rc = -EFAULT;
+ goto fail1;
+ }
+
+ /* Clear any previous over-temperature alert */
+ rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+ if (rc)
+ goto fail1;
+
+ /* Enable port 0 and port 1 outputs on IO expander */
+ cfg = 0x00;
+ rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+ if (rc)
+ goto fail1;
+ cfg = 0xff & ~(1 << P1_SPARE_LBN);
+ rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+ if (rc)
+ goto fail2;
+
+ /* Turn all power off then wait 1 sec. This ensures PHY is reset */
+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+ (0 << P0_EN_1V0X_LBN));
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+
+ schedule_timeout_uninterruptible(HZ);
+ count = 0;
+ do {
+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+ out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+ (1 << P0_X_TRST_LBN));
+ if (sfe4001_phy_flash_cfg)
+ out |= 1 << P0_EN_3V3X_LBN;
+
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+ msleep(10);
+
+ /* Turn on 1V power rail */
+ out &= ~(1 << P0_EN_1V0X_LBN);
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+
+ EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
+
+ schedule_timeout_uninterruptible(HZ);
+
+ /* Check DSP is powered */
+ rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
+ if (rc)
+ goto fail3;
+ if (in & (1 << P1_AFE_PWD_LBN))
+ goto done;
+
+ /* DSP doesn't look powered in flash config mode */
+ if (sfe4001_phy_flash_cfg)
+ goto done;
+ } while (++count < 20);
+
+ EFX_INFO(efx, "timed out waiting for power\n");
+ rc = -ETIMEDOUT;
+ goto fail3;
+
+done:
+ EFX_INFO(efx, "PHY is powered on\n");
+ return 0;
+
+fail3:
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ /* Disable port 1 outputs on IO expander */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
+fail2:
+ /* Disable port 0 outputs on IO expander */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
+fail1:
+ return rc;
+}
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
new file mode 100644
index 000000000000..34412f3d41c9
--- /dev/null
+++ b/drivers/net/sfc/spi.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_SPI_H
+#define EFX_SPI_H
+
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Basic SPI command set and bit definitions
+ *
+ *************************************************************************/
+
+/*
+ * Commands common to all known devices.
+ *
+ */
+
+/* Write status register */
+#define SPI_WRSR 0x01
+
+/* Write data to memory array */
+#define SPI_WRITE 0x02
+
+/* Read data from memory array */
+#define SPI_READ 0x03
+
+/* Reset write enable latch */
+#define SPI_WRDI 0x04
+
+/* Read status register */
+#define SPI_RDSR 0x05
+
+/* Set write enable latch */
+#define SPI_WREN 0x06
+
+/* SST: Enable write to status register */
+#define SPI_SST_EWSR 0x50
+
+/*
+ * Status register bits. Not all bits are supported on all devices.
+ *
+ */
+
+/* Write-protect pin enabled */
+#define SPI_STATUS_WPEN 0x80
+
+/* Block protection bit 2 */
+#define SPI_STATUS_BP2 0x10
+
+/* Block protection bit 1 */
+#define SPI_STATUS_BP1 0x08
+
+/* Block protection bit 0 */
+#define SPI_STATUS_BP0 0x04
+
+/* State of the write enable latch */
+#define SPI_STATUS_WEN 0x02
+
+/* Device busy flag */
+#define SPI_STATUS_NRDY 0x01
+
+#endif /* EFX_SPI_H */
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
new file mode 100644
index 000000000000..b1cd6deec01f
--- /dev/null
+++ b/drivers/net/sfc/tenxpress.c
@@ -0,0 +1,517 @@
+/****************************************************************************
+ * Driver for Solarflare 802.3an compliant PHY
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include "efx.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "falcon.h"
+#include "phy.h"
+#include "falcon_hwdefs.h"
+#include "boards.h"
+#include "mac.h"
+
+/* We expect these MMDs to be in the package */
+/* AN not here as mdio_check_mmds() requires STAT2 support */
+#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PHYXS)
+
+#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \
+ (1 << LOOPBACK_PCS) | \
+ (1 << LOOPBACK_PMAPMD) | \
+ (1 << LOOPBACK_NETWORK))
+
+/* We complain if we fail to see the link partner as 10G capable this many
+ * times in a row (must be > 1 as sampling the autoneg. registers is racy)
+ */
+#define MAX_BAD_LP_TRIES (5)
+
+/* Extended control register */
+#define PMA_PMD_XCONTROL_REG 0xc000
+#define PMA_PMD_LNPGA_POWERDOWN_LBN 8
+#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
+
+/* extended status register */
+#define PMA_PMD_XSTATUS_REG 0xc001
+#define PMA_PMD_XSTAT_FLP_LBN (12)
+
+/* LED control register */
+#define PMA_PMD_LED_CTRL_REG (0xc007)
+#define PMA_PMA_LED_ACTIVITY_LBN (3)
+
+/* LED function override register */
+#define PMA_PMD_LED_OVERR_REG (0xc009)
+/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
+#define PMA_PMD_LED_LINK_LBN (0)
+#define PMA_PMD_LED_SPEED_LBN (2)
+#define PMA_PMD_LED_TX_LBN (4)
+#define PMA_PMD_LED_RX_LBN (6)
+/* Override settings */
+#define PMA_PMD_LED_AUTO (0) /* H/W control */
+#define PMA_PMD_LED_ON (1)
+#define PMA_PMD_LED_OFF (2)
+#define PMA_PMD_LED_FLASH (3)
+/* All LEDs under hardware control */
+#define PMA_PMD_LED_FULL_AUTO (0)
+/* Green and Amber under hardware control, Red off */
+#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
+
+
+/* Self test (BIST) control register */
+#define PMA_PMD_BIST_CTRL_REG (0xc014)
+#define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */
+#define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */
+#define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */
+/* Self test status register */
+#define PMA_PMD_BIST_STAT_REG (0xc015)
+#define PMA_PMD_BIST_ENX_LBN (3)
+#define PMA_PMD_BIST_PMA_LBN (2)
+#define PMA_PMD_BIST_RXD_LBN (1)
+#define PMA_PMD_BIST_AFE_LBN (0)
+
+/* Special Software reset register */
+#define PMA_PMD_EXT_CTRL_REG 49152
+#define PMA_PMD_EXT_SSR_LBN 15
+
+#define BIST_MAX_DELAY (1000)
+#define BIST_POLL_DELAY (10)
+
+/* Misc register defines */
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
+#define CLK312_EN_LBN 3
+
+/* PHYXS registers */
+#define PHYXS_TEST1 (49162)
+#define LOOPBACK_NEAR_LBN (8)
+#define LOOPBACK_NEAR_WIDTH (1)
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG (0xd000)
+#define PCS_BOOT_FATAL_ERR_LBN (0)
+#define PCS_BOOT_PROGRESS_LBN (1)
+#define PCS_BOOT_PROGRESS_WIDTH (2)
+#define PCS_BOOT_COMPLETE_LBN (3)
+#define PCS_BOOT_MAX_DELAY (100)
+#define PCS_BOOT_POLL_DELAY (10)
+
+/* Time to wait between powering down the LNPGA and turning off the power
+ * rails */
+#define LNPGA_PDOWN_WAIT (HZ / 5)
+
+static int crc_error_reset_threshold = 100;
+module_param(crc_error_reset_threshold, int, 0644);
+MODULE_PARM_DESC(crc_error_reset_threshold,
+ "Max number of CRC errors before XAUI reset");
+
+struct tenxpress_phy_data {
+ enum tenxpress_state state;
+ enum efx_loopback_mode loopback_mode;
+ atomic_t bad_crc_count;
+ int tx_disabled;
+ int bad_lp_tries;
+};
+
+static int tenxpress_state_is(struct efx_nic *efx, int state)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ return (phy_data != NULL) && (state == phy_data->state);
+}
+
+void tenxpress_set_state(struct efx_nic *efx,
+ enum tenxpress_state state)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ if (phy_data != NULL)
+ phy_data->state = state;
+}
+
+void tenxpress_crc_err(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ if (phy_data != NULL)
+ atomic_inc(&phy_data->bad_crc_count);
+}
+
+/* Check that the C166 has booted successfully */
+static int tenxpress_phy_check(struct efx_nic *efx)
+{
+ int phy_id = efx->mii.phy_id;
+ int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
+ int boot_stat;
+
+ /* Wait for the boot to complete (or not) */
+ while (count) {
+ boot_stat = mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_PCS,
+ PCS_BOOT_STATUS_REG);
+ if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
+ break;
+ count--;
+ udelay(PCS_BOOT_POLL_DELAY);
+ }
+
+ if (!count) {
+ EFX_ERR(efx, "%s: PHY boot timed out. Last status "
+ "%x\n", __func__,
+ (boot_stat >> PCS_BOOT_PROGRESS_LBN) &
+ ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void tenxpress_reset_xaui(struct efx_nic *efx);
+
+static int tenxpress_init(struct efx_nic *efx)
+{
+ int rc, reg;
+
+ /* Turn on the clock */
+ reg = (1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id,
+ MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+ rc = tenxpress_phy_check(efx);
+ if (rc < 0)
+ return rc;
+
+ /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
+ reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_CTRL_REG, reg);
+
+ reg = PMA_PMD_LED_DEFAULT;
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+
+ return rc;
+}
+
+static int tenxpress_phy_init(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data;
+ int rc = 0;
+
+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+ efx->phy_data = phy_data;
+
+ tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
+
+ if (!sfe4001_phy_flash_cfg) {
+ rc = mdio_clause45_wait_reset_mmds(efx,
+ TENXPRESS_REQUIRED_DEVS);
+ if (rc < 0)
+ goto fail;
+ }
+
+ rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+ if (rc < 0)
+ goto fail;
+
+ rc = tenxpress_init(efx);
+ if (rc < 0)
+ goto fail;
+
+ schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
+
+ /* Let XGXS and SerDes out of reset and resets 10XPress */
+ falcon_reset_xaui(efx);
+
+ return 0;
+
+ fail:
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+ return rc;
+}
+
+static int tenxpress_special_reset(struct efx_nic *efx)
+{
+ int rc, reg;
+
+ EFX_TRACE(efx, "%s\n", __func__);
+
+ /* Initiate reset */
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG);
+ reg |= (1 << PMA_PMD_EXT_SSR_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_EXT_CTRL_REG, reg);
+
+ msleep(200);
+
+ /* Wait for the blocks to come out of reset */
+ rc = mdio_clause45_wait_reset_mmds(efx,
+ TENXPRESS_REQUIRED_DEVS);
+ if (rc < 0)
+ return rc;
+
+ /* Try and reconfigure the device */
+ rc = tenxpress_init(efx);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
+{
+ struct tenxpress_phy_data *pd = efx->phy_data;
+ int reg;
+
+ /* Nothing to do if all is well and was previously so. */
+ if (!(bad_lp || pd->bad_lp_tries))
+ return;
+
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
+
+ if (bad_lp)
+ pd->bad_lp_tries++;
+ else
+ pd->bad_lp_tries = 0;
+
+ if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
+ pd->bad_lp_tries = 0; /* Restart count */
+ reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
+ reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
+ EFX_ERR(efx, "This NIC appears to be plugged into"
+ " a port that is not 10GBASE-T capable.\n"
+ " This PHY is 10GBASE-T ONLY, so no link can"
+ " be established.\n");
+ } else {
+ reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
+ }
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+}
+
+/* Check link status and return a boolean OK value. If the link is NOT
+ * OK we have a quick rummage round to see if we appear to be plugged
+ * into a non-10GBT port and if so warn the user that they won't get
+ * link any time soon as we are 10GBT only, unless caller specified
+ * not to do this check (it isn't useful in loopback) */
+static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
+{
+ int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
+
+ if (ok) {
+ tenxpress_set_bad_lp(efx, 0);
+ } else if (check_lp) {
+ /* Are we plugged into the wrong sort of link? */
+ int bad_lp = 0;
+ int phy_id = efx->mii.phy_id;
+ int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+ MDIO_AN_STATUS);
+ int xphy_stat = mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_PMAPMD,
+ PMA_PMD_XSTATUS_REG);
+ /* Are we plugged into anything that sends FLPs? If
+ * not we can't distinguish between not being plugged
+ * in and being plugged into a non-AN antique. The FLP
+ * bit has the advantage of not clearing when autoneg
+ * restarts. */
+ if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
+ tenxpress_set_bad_lp(efx, 0);
+ return ok;
+ }
+
+ /* If it can do 10GBT it must be XNP capable */
+ bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
+ if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
+ bad_lp = !(mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
+ (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
+ }
+ tenxpress_set_bad_lp(efx, bad_lp);
+ }
+ return ok;
+}
+
+static void tenxpress_phyxs_loopback(struct efx_nic *efx)
+{
+ int phy_id = efx->mii.phy_id;
+ int ctrl1, ctrl2;
+
+ ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
+ PHYXS_TEST1);
+ if (efx->loopback_mode == LOOPBACK_PHYXS)
+ ctrl2 |= (1 << LOOPBACK_NEAR_LBN);
+ else
+ ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN);
+ if (ctrl1 != ctrl2)
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
+ PHYXS_TEST1, ctrl2);
+}
+
+static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ int loop_change = LOOPBACK_OUT_OF(phy_data, efx,
+ TENXPRESS_LOOPBACKS);
+
+ if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
+ return;
+
+ /* When coming out of transmit disable, coming out of low power
+ * mode, or moving out of any PHY internal loopback mode,
+ * perform a special software reset */
+ if ((phy_data->tx_disabled && !efx->tx_disabled) ||
+ loop_change) {
+ (void) tenxpress_special_reset(efx);
+ falcon_reset_xaui(efx);
+ }
+
+ mdio_clause45_transmit_disable(efx);
+ mdio_clause45_phy_reconfigure(efx);
+ tenxpress_phyxs_loopback(efx);
+
+ phy_data->tx_disabled = efx->tx_disabled;
+ phy_data->loopback_mode = efx->loopback_mode;
+ efx->link_up = tenxpress_link_ok(efx, 0);
+ efx->link_options = GM_LPA_10000FULL;
+}
+
+static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
+{
+ /* Nothing done here - LASI interrupts aren't reliable so poll */
+}
+
+
+/* Poll PHY for interrupt */
+static int tenxpress_phy_check_hw(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
+ int link_ok;
+
+ link_ok = phy_up && tenxpress_link_ok(efx, 1);
+
+ if (link_ok != efx->link_up)
+ falcon_xmac_sim_phy_event(efx);
+
+ /* Nothing to check if we've already shut down the PHY */
+ if (!phy_up)
+ return 0;
+
+ if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
+ EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
+ falcon_reset_xaui(efx);
+ atomic_set(&phy_data->bad_crc_count, 0);
+ }
+
+ return 0;
+}
+
+static void tenxpress_phy_fini(struct efx_nic *efx)
+{
+ int reg;
+
+ /* Power down the LNPGA */
+ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_XCONTROL_REG, reg);
+
+ /* Waiting here ensures that the board fini, which can turn off the
+ * power to the PHY, won't get run until the LNPGA powerdown has been
+ * given long enough to complete. */
+ schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+}
+
+
+/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
+ * (which probably aren't wired anyway) are left in AUTO mode */
+void tenxpress_phy_blink(struct efx_nic *efx, int blink)
+{
+ int reg;
+
+ if (blink)
+ reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
+ (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
+ (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
+ else
+ reg = PMA_PMD_LED_DEFAULT;
+
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+}
+
+static void tenxpress_reset_xaui(struct efx_nic *efx)
+{
+ int phy = efx->mii.phy_id;
+ int clk_ctrl, test_select, soft_rst2;
+
+ /* Real work is done on clock_ctrl other resets are thought to be
+ * optional but make the reset more reliable
+ */
+
+ /* Read */
+ clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG);
+ test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG);
+ soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG);
+
+ /* Put in reset */
+ test_select &= ~(1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG, test_select);
+
+ soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG, soft_rst2);
+
+ clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG, clk_ctrl);
+ udelay(10);
+
+ /* Remove reset */
+ clk_ctrl |= (1 << PLL312_RST_N_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG, clk_ctrl);
+ udelay(10);
+
+ soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG, soft_rst2);
+ udelay(10);
+
+ test_select |= (1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG, test_select);
+ udelay(10);
+}
+
+struct efx_phy_operations falcon_tenxpress_phy_ops = {
+ .init = tenxpress_phy_init,
+ .reconfigure = tenxpress_phy_reconfigure,
+ .check_hw = tenxpress_phy_check_hw,
+ .fini = tenxpress_phy_fini,
+ .clear_interrupt = tenxpress_phy_clear_interrupt,
+ .reset_xaui = tenxpress_reset_xaui,
+ .mmds = TENXPRESS_REQUIRED_DEVS,
+ .loopbacks = TENXPRESS_LOOPBACKS,
+};
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
new file mode 100644
index 000000000000..9b436f5b4888
--- /dev/null
+++ b/drivers/net/sfc/tx.c
@@ -0,0 +1,1116 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/pci.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/highmem.h>
+#include "net_driver.h"
+#include "tx.h"
+#include "efx.h"
+#include "falcon.h"
+#include "workarounds.h"
+
+/*
+ * TX descriptor ring full threshold
+ *
+ * The tx_queue descriptor ring fill-level must fall below this value
+ * before we restart the netif queue
+ */
+#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \
+ (_tx_queue->efx->type->txd_ring_mask / 2u)
+
+/* We want to be able to nest calls to netif_stop_queue(), since each
+ * channel can have an individual stop on the queue.
+ */
+void efx_stop_queue(struct efx_nic *efx)
+{
+ spin_lock_bh(&efx->netif_stop_lock);
+ EFX_TRACE(efx, "stop TX queue\n");
+
+ atomic_inc(&efx->netif_stop_count);
+ netif_stop_queue(efx->net_dev);
+
+ spin_unlock_bh(&efx->netif_stop_lock);
+}
+
+/* Wake netif's TX queue
+ * We want to be able to nest calls to netif_stop_queue(), since each
+ * channel can have an individual stop on the queue.
+ */
+inline void efx_wake_queue(struct efx_nic *efx)
+{
+ local_bh_disable();
+ if (atomic_dec_and_lock(&efx->netif_stop_count,
+ &efx->netif_stop_lock)) {
+ EFX_TRACE(efx, "waking TX queue\n");
+ netif_wake_queue(efx->net_dev);
+ spin_unlock(&efx->netif_stop_lock);
+ }
+ local_bh_enable();
+}
+
+static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
+ struct efx_tx_buffer *buffer)
+{
+ if (buffer->unmap_len) {
+ struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+ if (buffer->unmap_single)
+ pci_unmap_single(pci_dev, buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ else
+ pci_unmap_page(pci_dev, buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ buffer->unmap_len = 0;
+ buffer->unmap_single = 0;
+ }
+
+ if (buffer->skb) {
+ dev_kfree_skb_any((struct sk_buff *) buffer->skb);
+ buffer->skb = NULL;
+ EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
+ "complete\n", tx_queue->queue, read_ptr);
+ }
+}
+
+/**
+ * struct efx_tso_header - a DMA mapped buffer for packet headers
+ * @next: Linked list of free ones.
+ * The list is protected by the TX queue lock.
+ * @dma_unmap_len: Length to unmap for an oversize buffer, or 0.
+ * @dma_addr: The DMA address of the header below.
+ *
+ * This controls the memory used for a TSO header. Use TSOH_DATA()
+ * to find the packet header data. Use TSOH_SIZE() to calculate the
+ * total size required for a given packet header length. TSO headers
+ * in the free list are exactly %TSOH_STD_SIZE bytes in size.
+ */
+struct efx_tso_header {
+ union {
+ struct efx_tso_header *next;
+ size_t unmap_len;
+ };
+ dma_addr_t dma_addr;
+};
+
+static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb);
+static void efx_fini_tso(struct efx_tx_queue *tx_queue);
+static void efx_tsoh_heap_free(struct efx_tx_queue *tx_queue,
+ struct efx_tso_header *tsoh);
+
+static inline void efx_tsoh_free(struct efx_tx_queue *tx_queue,
+ struct efx_tx_buffer *buffer)
+{
+ if (buffer->tsoh) {
+ if (likely(!buffer->tsoh->unmap_len)) {
+ buffer->tsoh->next = tx_queue->tso_headers_free;
+ tx_queue->tso_headers_free = buffer->tsoh;
+ } else {
+ efx_tsoh_heap_free(tx_queue, buffer->tsoh);
+ }
+ buffer->tsoh = NULL;
+ }
+}
+
+
+/*
+ * Add a socket buffer to a TX queue
+ *
+ * This maps all fragments of a socket buffer for DMA and adds them to
+ * the TX queue. The queue's insert pointer will be incremented by
+ * the number of fragments in the socket buffer.
+ *
+ * If any DMA mapping fails, any mapped fragments will be unmapped,
+ * the queue's insert pointer will be restored to its original value.
+ *
+ * Returns NETDEV_TX_OK or NETDEV_TX_BUSY
+ * You must hold netif_tx_lock() to call this function.
+ */
+static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct pci_dev *pci_dev = efx->pci_dev;
+ struct efx_tx_buffer *buffer;
+ skb_frag_t *fragment;
+ struct page *page;
+ int page_offset;
+ unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
+ dma_addr_t dma_addr, unmap_addr = 0;
+ unsigned int dma_len;
+ unsigned unmap_single;
+ int q_space, i = 0;
+ int rc = NETDEV_TX_OK;
+
+ EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
+
+ if (skb_shinfo((struct sk_buff *)skb)->gso_size)
+ return efx_enqueue_skb_tso(tx_queue, skb);
+
+ /* Get size of the initial fragment */
+ len = skb_headlen(skb);
+
+ fill_level = tx_queue->insert_count - tx_queue->old_read_count;
+ q_space = efx->type->txd_ring_mask - 1 - fill_level;
+
+ /* Map for DMA. Use pci_map_single rather than pci_map_page
+ * since this is more efficient on machines with sparse
+ * memory.
+ */
+ unmap_single = 1;
+ dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+
+ /* Process all fragments */
+ while (1) {
+ if (unlikely(pci_dma_mapping_error(dma_addr)))
+ goto pci_err;
+
+ /* Store fields for marking in the per-fragment final
+ * descriptor */
+ unmap_len = len;
+ unmap_addr = dma_addr;
+
+ /* Add to TX queue, splitting across DMA boundaries */
+ do {
+ if (unlikely(q_space-- <= 0)) {
+ /* It might be that completions have
+ * happened since the xmit path last
+ * checked. Update the xmit path's
+ * copy of read_count.
+ */
+ ++tx_queue->stopped;
+ /* This memory barrier protects the
+ * change of stopped from the access
+ * of read_count. */
+ smp_mb();
+ tx_queue->old_read_count =
+ *(volatile unsigned *)
+ &tx_queue->read_count;
+ fill_level = (tx_queue->insert_count
+ - tx_queue->old_read_count);
+ q_space = (efx->type->txd_ring_mask - 1 -
+ fill_level);
+ if (unlikely(q_space-- <= 0))
+ goto stop;
+ smp_mb();
+ --tx_queue->stopped;
+ }
+
+ insert_ptr = (tx_queue->insert_count &
+ efx->type->txd_ring_mask);
+ buffer = &tx_queue->buffer[insert_ptr];
+ efx_tsoh_free(tx_queue, buffer);
+ EFX_BUG_ON_PARANOID(buffer->tsoh);
+ EFX_BUG_ON_PARANOID(buffer->skb);
+ EFX_BUG_ON_PARANOID(buffer->len);
+ EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+ EFX_BUG_ON_PARANOID(buffer->unmap_len);
+
+ dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
+ if (likely(dma_len > len))
+ dma_len = len;
+
+ misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
+ if (misalign && dma_len + misalign > 512)
+ dma_len = 512 - misalign;
+
+ /* Fill out per descriptor fields */
+ buffer->len = dma_len;
+ buffer->dma_addr = dma_addr;
+ len -= dma_len;
+ dma_addr += dma_len;
+ ++tx_queue->insert_count;
+ } while (len);
+
+ /* Transfer ownership of the unmapping to the final buffer */
+ buffer->unmap_addr = unmap_addr;
+ buffer->unmap_single = unmap_single;
+ buffer->unmap_len = unmap_len;
+ unmap_len = 0;
+
+ /* Get address and size of next fragment */
+ if (i >= skb_shinfo(skb)->nr_frags)
+ break;
+ fragment = &skb_shinfo(skb)->frags[i];
+ len = fragment->size;
+ page = fragment->page;
+ page_offset = fragment->page_offset;
+ i++;
+ /* Map for DMA */
+ unmap_single = 0;
+ dma_addr = pci_map_page(pci_dev, page, page_offset, len,
+ PCI_DMA_TODEVICE);
+ }
+
+ /* Transfer ownership of the skb to the final buffer */
+ buffer->skb = skb;
+ buffer->continuation = 0;
+
+ /* Pass off to hardware */
+ falcon_push_buffers(tx_queue);
+
+ return NETDEV_TX_OK;
+
+ pci_err:
+ EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
+ "fragments for DMA\n", tx_queue->queue, skb->len,
+ skb_shinfo(skb)->nr_frags + 1);
+
+ /* Mark the packet as transmitted, and free the SKB ourselves */
+ dev_kfree_skb_any((struct sk_buff *)skb);
+ goto unwind;
+
+ stop:
+ rc = NETDEV_TX_BUSY;
+
+ if (tx_queue->stopped == 1)
+ efx_stop_queue(efx);
+
+ unwind:
+ /* Work backwards until we hit the original insert pointer value */
+ while (tx_queue->insert_count != tx_queue->write_count) {
+ --tx_queue->insert_count;
+ insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+ buffer = &tx_queue->buffer[insert_ptr];
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->len = 0;
+ }
+
+ /* Free the fragment we were mid-way through pushing */
+ if (unmap_len)
+ pci_unmap_page(pci_dev, unmap_addr, unmap_len,
+ PCI_DMA_TODEVICE);
+
+ return rc;
+}
+
+/* Remove packets from the TX queue
+ *
+ * This removes packets from the TX queue, up to and including the
+ * specified index.
+ */
+static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
+ unsigned int index)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned int stop_index, read_ptr;
+ unsigned int mask = tx_queue->efx->type->txd_ring_mask;
+
+ stop_index = (index + 1) & mask;
+ read_ptr = tx_queue->read_count & mask;
+
+ while (read_ptr != stop_index) {
+ struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
+ if (unlikely(buffer->len == 0)) {
+ EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
+ "completion id %x\n", tx_queue->queue,
+ read_ptr);
+ efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
+ return;
+ }
+
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->continuation = 1;
+ buffer->len = 0;
+
+ ++tx_queue->read_count;
+ read_ptr = tx_queue->read_count & mask;
+ }
+}
+
+/* Initiate a packet transmission on the specified TX queue.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ *
+ * This function is split out from efx_hard_start_xmit to allow the
+ * loopback test to direct packets via specific TX queues. It is
+ * therefore a non-static inline, so as not to penalise performance
+ * for non-loopback transmissions.
+ *
+ * Context: netif_tx_lock held
+ */
+inline int efx_xmit(struct efx_nic *efx,
+ struct efx_tx_queue *tx_queue, struct sk_buff *skb)
+{
+ int rc;
+
+ /* Map fragments for DMA and add to TX queue */
+ rc = efx_enqueue_skb(tx_queue, skb);
+ if (unlikely(rc != NETDEV_TX_OK))
+ goto out;
+
+ /* Update last TX timer */
+ efx->net_dev->trans_start = jiffies;
+
+ out:
+ return rc;
+}
+
+/* Initiate a packet transmission. We use one channel per CPU
+ * (sharing when we have more CPUs than channels). On Falcon, the TX
+ * completion events will be directed back to the CPU that transmitted
+ * the packet, which should be cache-efficient.
+ *
+ * Context: non-blocking.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ */
+int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ return efx_xmit(efx, &efx->tx_queue[0], skb);
+}
+
+void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
+{
+ unsigned fill_level;
+ struct efx_nic *efx = tx_queue->efx;
+
+ EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask);
+
+ efx_dequeue_buffers(tx_queue, index);
+
+ /* See if we need to restart the netif queue. This barrier
+ * separates the update of read_count from the test of
+ * stopped. */
+ smp_mb();
+ if (unlikely(tx_queue->stopped)) {
+ fill_level = tx_queue->insert_count - tx_queue->read_count;
+ if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
+ EFX_BUG_ON_PARANOID(!NET_DEV_REGISTERED(efx));
+
+ /* Do this under netif_tx_lock(), to avoid racing
+ * with efx_xmit(). */
+ netif_tx_lock(efx->net_dev);
+ if (tx_queue->stopped) {
+ tx_queue->stopped = 0;
+ efx_wake_queue(efx);
+ }
+ netif_tx_unlock(efx->net_dev);
+ }
+ }
+}
+
+int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned int txq_size;
+ int i, rc;
+
+ EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
+
+ /* Allocate software ring */
+ txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
+ tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
+ if (!tx_queue->buffer) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+ for (i = 0; i <= efx->type->txd_ring_mask; ++i)
+ tx_queue->buffer[i].continuation = 1;
+
+ /* Allocate hardware ring */
+ rc = falcon_probe_tx(tx_queue);
+ if (rc)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ kfree(tx_queue->buffer);
+ tx_queue->buffer = NULL;
+ fail1:
+ tx_queue->used = 0;
+
+ return rc;
+}
+
+int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
+
+ tx_queue->insert_count = 0;
+ tx_queue->write_count = 0;
+ tx_queue->read_count = 0;
+ tx_queue->old_read_count = 0;
+ BUG_ON(tx_queue->stopped);
+
+ /* Set up TX descriptor ring */
+ return falcon_init_tx(tx_queue);
+}
+
+void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
+{
+ struct efx_tx_buffer *buffer;
+
+ if (!tx_queue->buffer)
+ return;
+
+ /* Free any buffers left in the ring */
+ while (tx_queue->read_count != tx_queue->write_count) {
+ buffer = &tx_queue->buffer[tx_queue->read_count &
+ tx_queue->efx->type->txd_ring_mask];
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->continuation = 1;
+ buffer->len = 0;
+
+ ++tx_queue->read_count;
+ }
+}
+
+void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
+
+ /* Flush TX queue, remove descriptor ring */
+ falcon_fini_tx(tx_queue);
+
+ efx_release_tx_buffers(tx_queue);
+
+ /* Free up TSO header cache */
+ efx_fini_tso(tx_queue);
+
+ /* Release queue's stop on port, if any */
+ if (tx_queue->stopped) {
+ tx_queue->stopped = 0;
+ efx_wake_queue(tx_queue->efx);
+ }
+}
+
+void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
+ falcon_remove_tx(tx_queue);
+
+ kfree(tx_queue->buffer);
+ tx_queue->buffer = NULL;
+ tx_queue->used = 0;
+}
+
+
+/* Efx TCP segmentation acceleration.
+ *
+ * Why? Because by doing it here in the driver we can go significantly
+ * faster than the GSO.
+ *
+ * Requires TX checksum offload support.
+ */
+
+/* Number of bytes inserted at the start of a TSO header buffer,
+ * similar to NET_IP_ALIGN.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define TSOH_OFFSET 0
+#else
+#define TSOH_OFFSET NET_IP_ALIGN
+#endif
+
+#define TSOH_BUFFER(tsoh) ((u8 *)(tsoh + 1) + TSOH_OFFSET)
+
+/* Total size of struct efx_tso_header, buffer and padding */
+#define TSOH_SIZE(hdr_len) \
+ (sizeof(struct efx_tso_header) + TSOH_OFFSET + hdr_len)
+
+/* Size of blocks on free list. Larger blocks must be allocated from
+ * the heap.
+ */
+#define TSOH_STD_SIZE 128
+
+#define PTR_DIFF(p1, p2) ((u8 *)(p1) - (u8 *)(p2))
+#define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data)
+#define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data)
+#define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data)
+
+/**
+ * struct tso_state - TSO state for an SKB
+ * @remaining_len: Bytes of data we've yet to segment
+ * @seqnum: Current sequence number
+ * @packet_space: Remaining space in current packet
+ * @ifc: Input fragment cursor.
+ * Where we are in the current fragment of the incoming SKB. These
+ * values get updated in place when we split a fragment over
+ * multiple packets.
+ * @p: Parameters.
+ * These values are set once at the start of the TSO send and do
+ * not get changed as the routine progresses.
+ *
+ * The state used during segmentation. It is put into this data structure
+ * just to make it easy to pass into inline functions.
+ */
+struct tso_state {
+ unsigned remaining_len;
+ unsigned seqnum;
+ unsigned packet_space;
+
+ struct {
+ /* DMA address of current position */
+ dma_addr_t dma_addr;
+ /* Remaining length */
+ unsigned int len;
+ /* DMA address and length of the whole fragment */
+ unsigned int unmap_len;
+ dma_addr_t unmap_addr;
+ struct page *page;
+ unsigned page_off;
+ } ifc;
+
+ struct {
+ /* The number of bytes of header */
+ unsigned int header_length;
+
+ /* The number of bytes to put in each outgoing segment. */
+ int full_packet_size;
+
+ /* Current IPv4 ID, host endian. */
+ unsigned ipv4_id;
+ } p;
+};
+
+
+/*
+ * Verify that our various assumptions about sk_buffs and the conditions
+ * under which TSO will be attempted hold true.
+ */
+static inline void efx_tso_check_safe(const struct sk_buff *skb)
+{
+ EFX_BUG_ON_PARANOID(skb->protocol != htons(ETH_P_IP));
+ EFX_BUG_ON_PARANOID(((struct ethhdr *)skb->data)->h_proto !=
+ skb->protocol);
+ EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP);
+ EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data)
+ + (tcp_hdr(skb)->doff << 2u)) >
+ skb_headlen(skb));
+}
+
+
+/*
+ * Allocate a page worth of efx_tso_header structures, and string them
+ * into the tx_queue->tso_headers_free linked list. Return 0 or -ENOMEM.
+ */
+static int efx_tsoh_block_alloc(struct efx_tx_queue *tx_queue)
+{
+
+ struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+ struct efx_tso_header *tsoh;
+ dma_addr_t dma_addr;
+ u8 *base_kva, *kva;
+
+ base_kva = pci_alloc_consistent(pci_dev, PAGE_SIZE, &dma_addr);
+ if (base_kva == NULL) {
+ EFX_ERR(tx_queue->efx, "Unable to allocate page for TSO"
+ " headers\n");
+ return -ENOMEM;
+ }
+
+ /* pci_alloc_consistent() allocates pages. */
+ EFX_BUG_ON_PARANOID(dma_addr & (PAGE_SIZE - 1u));
+
+ for (kva = base_kva; kva < base_kva + PAGE_SIZE; kva += TSOH_STD_SIZE) {
+ tsoh = (struct efx_tso_header *)kva;
+ tsoh->dma_addr = dma_addr + (TSOH_BUFFER(tsoh) - base_kva);
+ tsoh->next = tx_queue->tso_headers_free;
+ tx_queue->tso_headers_free = tsoh;
+ }
+
+ return 0;
+}
+
+
+/* Free up a TSO header, and all others in the same page. */
+static void efx_tsoh_block_free(struct efx_tx_queue *tx_queue,
+ struct efx_tso_header *tsoh,
+ struct pci_dev *pci_dev)
+{
+ struct efx_tso_header **p;
+ unsigned long base_kva;
+ dma_addr_t base_dma;
+
+ base_kva = (unsigned long)tsoh & PAGE_MASK;
+ base_dma = tsoh->dma_addr & PAGE_MASK;
+
+ p = &tx_queue->tso_headers_free;
+ while (*p != NULL)
+ if (((unsigned long)*p & PAGE_MASK) == base_kva)
+ *p = (*p)->next;
+ else
+ p = &(*p)->next;
+
+ pci_free_consistent(pci_dev, PAGE_SIZE, (void *)base_kva, base_dma);
+}
+
+static struct efx_tso_header *
+efx_tsoh_heap_alloc(struct efx_tx_queue *tx_queue, size_t header_len)
+{
+ struct efx_tso_header *tsoh;
+
+ tsoh = kmalloc(TSOH_SIZE(header_len), GFP_ATOMIC | GFP_DMA);
+ if (unlikely(!tsoh))
+ return NULL;
+
+ tsoh->dma_addr = pci_map_single(tx_queue->efx->pci_dev,
+ TSOH_BUFFER(tsoh), header_len,
+ PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(tsoh->dma_addr))) {
+ kfree(tsoh);
+ return NULL;
+ }
+
+ tsoh->unmap_len = header_len;
+ return tsoh;
+}
+
+static void
+efx_tsoh_heap_free(struct efx_tx_queue *tx_queue, struct efx_tso_header *tsoh)
+{
+ pci_unmap_single(tx_queue->efx->pci_dev,
+ tsoh->dma_addr, tsoh->unmap_len,
+ PCI_DMA_TODEVICE);
+ kfree(tsoh);
+}
+
+/**
+ * efx_tx_queue_insert - push descriptors onto the TX queue
+ * @tx_queue: Efx TX queue
+ * @dma_addr: DMA address of fragment
+ * @len: Length of fragment
+ * @skb: Only non-null for end of last segment
+ * @end_of_packet: True if last fragment in a packet
+ * @unmap_addr: DMA address of fragment for unmapping
+ * @unmap_len: Only set this in last segment of a fragment
+ *
+ * Push descriptors onto the TX queue. Return 0 on success or 1 if
+ * @tx_queue full.
+ */
+static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
+ dma_addr_t dma_addr, unsigned len,
+ const struct sk_buff *skb, int end_of_packet,
+ dma_addr_t unmap_addr, unsigned unmap_len)
+{
+ struct efx_tx_buffer *buffer;
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned dma_len, fill_level, insert_ptr, misalign;
+ int q_space;
+
+ EFX_BUG_ON_PARANOID(len <= 0);
+
+ fill_level = tx_queue->insert_count - tx_queue->old_read_count;
+ /* -1 as there is no way to represent all descriptors used */
+ q_space = efx->type->txd_ring_mask - 1 - fill_level;
+
+ while (1) {
+ if (unlikely(q_space-- <= 0)) {
+ /* It might be that completions have happened
+ * since the xmit path last checked. Update
+ * the xmit path's copy of read_count.
+ */
+ ++tx_queue->stopped;
+ /* This memory barrier protects the change of
+ * stopped from the access of read_count. */
+ smp_mb();
+ tx_queue->old_read_count =
+ *(volatile unsigned *)&tx_queue->read_count;
+ fill_level = (tx_queue->insert_count
+ - tx_queue->old_read_count);
+ q_space = efx->type->txd_ring_mask - 1 - fill_level;
+ if (unlikely(q_space-- <= 0))
+ return 1;
+ smp_mb();
+ --tx_queue->stopped;
+ }
+
+ insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+ buffer = &tx_queue->buffer[insert_ptr];
+ ++tx_queue->insert_count;
+
+ EFX_BUG_ON_PARANOID(tx_queue->insert_count -
+ tx_queue->read_count >
+ efx->type->txd_ring_mask);
+
+ efx_tsoh_free(tx_queue, buffer);
+ EFX_BUG_ON_PARANOID(buffer->len);
+ EFX_BUG_ON_PARANOID(buffer->unmap_len);
+ EFX_BUG_ON_PARANOID(buffer->skb);
+ EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+ EFX_BUG_ON_PARANOID(buffer->tsoh);
+
+ buffer->dma_addr = dma_addr;
+
+ /* Ensure we do not cross a boundary unsupported by H/W */
+ dma_len = (~dma_addr & efx->type->tx_dma_mask) + 1;
+
+ misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
+ if (misalign && dma_len + misalign > 512)
+ dma_len = 512 - misalign;
+
+ /* If there is enough space to send then do so */
+ if (dma_len >= len)
+ break;
+
+ buffer->len = dma_len; /* Don't set the other members */
+ dma_addr += dma_len;
+ len -= dma_len;
+ }
+
+ EFX_BUG_ON_PARANOID(!len);
+ buffer->len = len;
+ buffer->skb = skb;
+ buffer->continuation = !end_of_packet;
+ buffer->unmap_addr = unmap_addr;
+ buffer->unmap_len = unmap_len;
+ return 0;
+}
+
+
+/*
+ * Put a TSO header into the TX queue.
+ *
+ * This is special-cased because we know that it is small enough to fit in
+ * a single fragment, and we know it doesn't cross a page boundary. It
+ * also allows us to not worry about end-of-packet etc.
+ */
+static inline void efx_tso_put_header(struct efx_tx_queue *tx_queue,
+ struct efx_tso_header *tsoh, unsigned len)
+{
+ struct efx_tx_buffer *buffer;
+
+ buffer = &tx_queue->buffer[tx_queue->insert_count &
+ tx_queue->efx->type->txd_ring_mask];
+ efx_tsoh_free(tx_queue, buffer);
+ EFX_BUG_ON_PARANOID(buffer->len);
+ EFX_BUG_ON_PARANOID(buffer->unmap_len);
+ EFX_BUG_ON_PARANOID(buffer->skb);
+ EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+ EFX_BUG_ON_PARANOID(buffer->tsoh);
+ buffer->len = len;
+ buffer->dma_addr = tsoh->dma_addr;
+ buffer->tsoh = tsoh;
+
+ ++tx_queue->insert_count;
+}
+
+
+/* Remove descriptors put into a tx_queue. */
+static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
+{
+ struct efx_tx_buffer *buffer;
+
+ /* Work backwards until we hit the original insert pointer value */
+ while (tx_queue->insert_count != tx_queue->write_count) {
+ --tx_queue->insert_count;
+ buffer = &tx_queue->buffer[tx_queue->insert_count &
+ tx_queue->efx->type->txd_ring_mask];
+ efx_tsoh_free(tx_queue, buffer);
+ EFX_BUG_ON_PARANOID(buffer->skb);
+ buffer->len = 0;
+ buffer->continuation = 1;
+ if (buffer->unmap_len) {
+ pci_unmap_page(tx_queue->efx->pci_dev,
+ buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ buffer->unmap_len = 0;
+ }
+ }
+}
+
+
+/* Parse the SKB header and initialise state. */
+static inline void tso_start(struct tso_state *st, const struct sk_buff *skb)
+{
+ /* All ethernet/IP/TCP headers combined size is TCP header size
+ * plus offset of TCP header relative to start of packet.
+ */
+ st->p.header_length = ((tcp_hdr(skb)->doff << 2u)
+ + PTR_DIFF(tcp_hdr(skb), skb->data));
+ st->p.full_packet_size = (st->p.header_length
+ + skb_shinfo(skb)->gso_size);
+
+ st->p.ipv4_id = ntohs(ip_hdr(skb)->id);
+ st->seqnum = ntohl(tcp_hdr(skb)->seq);
+
+ EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg);
+ EFX_BUG_ON_PARANOID(tcp_hdr(skb)->syn);
+ EFX_BUG_ON_PARANOID(tcp_hdr(skb)->rst);
+
+ st->packet_space = st->p.full_packet_size;
+ st->remaining_len = skb->len - st->p.header_length;
+}
+
+
+/**
+ * tso_get_fragment - record fragment details and map for DMA
+ * @st: TSO state
+ * @efx: Efx NIC
+ * @data: Pointer to fragment data
+ * @len: Length of fragment
+ *
+ * Record fragment details and map for DMA. Return 0 on success, or
+ * -%ENOMEM if DMA mapping fails.
+ */
+static inline int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
+ int len, struct page *page, int page_off)
+{
+
+ st->ifc.unmap_addr = pci_map_page(efx->pci_dev, page, page_off,
+ len, PCI_DMA_TODEVICE);
+ if (likely(!pci_dma_mapping_error(st->ifc.unmap_addr))) {
+ st->ifc.unmap_len = len;
+ st->ifc.len = len;
+ st->ifc.dma_addr = st->ifc.unmap_addr;
+ st->ifc.page = page;
+ st->ifc.page_off = page_off;
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+
+/**
+ * tso_fill_packet_with_fragment - form descriptors for the current fragment
+ * @tx_queue: Efx TX queue
+ * @skb: Socket buffer
+ * @st: TSO state
+ *
+ * Form descriptors for the current fragment, until we reach the end
+ * of fragment or end-of-packet. Return 0 on success, 1 if not enough
+ * space in @tx_queue.
+ */
+static inline int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb,
+ struct tso_state *st)
+{
+
+ int n, end_of_packet, rc;
+
+ if (st->ifc.len == 0)
+ return 0;
+ if (st->packet_space == 0)
+ return 0;
+
+ EFX_BUG_ON_PARANOID(st->ifc.len <= 0);
+ EFX_BUG_ON_PARANOID(st->packet_space <= 0);
+
+ n = min(st->ifc.len, st->packet_space);
+
+ st->packet_space -= n;
+ st->remaining_len -= n;
+ st->ifc.len -= n;
+ st->ifc.page_off += n;
+ end_of_packet = st->remaining_len == 0 || st->packet_space == 0;
+
+ rc = efx_tx_queue_insert(tx_queue, st->ifc.dma_addr, n,
+ st->remaining_len ? NULL : skb,
+ end_of_packet, st->ifc.unmap_addr,
+ st->ifc.len ? 0 : st->ifc.unmap_len);
+
+ st->ifc.dma_addr += n;
+
+ return rc;
+}
+
+
+/**
+ * tso_start_new_packet - generate a new header and prepare for the new packet
+ * @tx_queue: Efx TX queue
+ * @skb: Socket buffer
+ * @st: TSO state
+ *
+ * Generate a new header and prepare for the new packet. Return 0 on
+ * success, or -1 if failed to alloc header.
+ */
+static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb,
+ struct tso_state *st)
+{
+ struct efx_tso_header *tsoh;
+ struct iphdr *tsoh_iph;
+ struct tcphdr *tsoh_th;
+ unsigned ip_length;
+ u8 *header;
+
+ /* Allocate a DMA-mapped header buffer. */
+ if (likely(TSOH_SIZE(st->p.header_length) <= TSOH_STD_SIZE)) {
+ if (tx_queue->tso_headers_free == NULL)
+ if (efx_tsoh_block_alloc(tx_queue))
+ return -1;
+ EFX_BUG_ON_PARANOID(!tx_queue->tso_headers_free);
+ tsoh = tx_queue->tso_headers_free;
+ tx_queue->tso_headers_free = tsoh->next;
+ tsoh->unmap_len = 0;
+ } else {
+ tx_queue->tso_long_headers++;
+ tsoh = efx_tsoh_heap_alloc(tx_queue, st->p.header_length);
+ if (unlikely(!tsoh))
+ return -1;
+ }
+
+ header = TSOH_BUFFER(tsoh);
+ tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb));
+ tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb));
+
+ /* Copy and update the headers. */
+ memcpy(header, skb->data, st->p.header_length);
+
+ tsoh_th->seq = htonl(st->seqnum);
+ st->seqnum += skb_shinfo(skb)->gso_size;
+ if (st->remaining_len > skb_shinfo(skb)->gso_size) {
+ /* This packet will not finish the TSO burst. */
+ ip_length = st->p.full_packet_size - ETH_HDR_LEN(skb);
+ tsoh_th->fin = 0;
+ tsoh_th->psh = 0;
+ } else {
+ /* This packet will be the last in the TSO burst. */
+ ip_length = (st->p.header_length - ETH_HDR_LEN(skb)
+ + st->remaining_len);
+ tsoh_th->fin = tcp_hdr(skb)->fin;
+ tsoh_th->psh = tcp_hdr(skb)->psh;
+ }
+ tsoh_iph->tot_len = htons(ip_length);
+
+ /* Linux leaves suitable gaps in the IP ID space for us to fill. */
+ tsoh_iph->id = htons(st->p.ipv4_id);
+ st->p.ipv4_id++;
+
+ st->packet_space = skb_shinfo(skb)->gso_size;
+ ++tx_queue->tso_packets;
+
+ /* Form a descriptor for this header. */
+ efx_tso_put_header(tx_queue, tsoh, st->p.header_length);
+
+ return 0;
+}
+
+
+/**
+ * efx_enqueue_skb_tso - segment and transmit a TSO socket buffer
+ * @tx_queue: Efx TX queue
+ * @skb: Socket buffer
+ *
+ * Context: You must hold netif_tx_lock() to call this function.
+ *
+ * Add socket buffer @skb to @tx_queue, doing TSO or return != 0 if
+ * @skb was not enqueued. In all cases @skb is consumed. Return
+ * %NETDEV_TX_OK or %NETDEV_TX_BUSY.
+ */
+static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb)
+{
+ int frag_i, rc, rc2 = NETDEV_TX_OK;
+ struct tso_state state;
+ skb_frag_t *f;
+
+ /* Verify TSO is safe - these checks should never fail. */
+ efx_tso_check_safe(skb);
+
+ EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
+
+ tso_start(&state, skb);
+
+ /* Assume that skb header area contains exactly the headers, and
+ * all payload is in the frag list.
+ */
+ if (skb_headlen(skb) == state.p.header_length) {
+ /* Grab the first payload fragment. */
+ EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags < 1);
+ frag_i = 0;
+ f = &skb_shinfo(skb)->frags[frag_i];
+ rc = tso_get_fragment(&state, tx_queue->efx,
+ f->size, f->page, f->page_offset);
+ if (rc)
+ goto mem_err;
+ } else {
+ /* It may look like this code fragment assumes that the
+ * skb->data portion does not cross a page boundary, but
+ * that is not the case. It is guaranteed to be direct
+ * mapped memory, and therefore is physically contiguous,
+ * and so DMA will work fine. kmap_atomic() on this region
+ * will just return the direct mapping, so that will work
+ * too.
+ */
+ int page_off = (unsigned long)skb->data & (PAGE_SIZE - 1);
+ int hl = state.p.header_length;
+ rc = tso_get_fragment(&state, tx_queue->efx,
+ skb_headlen(skb) - hl,
+ virt_to_page(skb->data), page_off + hl);
+ if (rc)
+ goto mem_err;
+ frag_i = -1;
+ }
+
+ if (tso_start_new_packet(tx_queue, skb, &state) < 0)
+ goto mem_err;
+
+ while (1) {
+ rc = tso_fill_packet_with_fragment(tx_queue, skb, &state);
+ if (unlikely(rc))
+ goto stop;
+
+ /* Move onto the next fragment? */
+ if (state.ifc.len == 0) {
+ if (++frag_i >= skb_shinfo(skb)->nr_frags)
+ /* End of payload reached. */
+ break;
+ f = &skb_shinfo(skb)->frags[frag_i];
+ rc = tso_get_fragment(&state, tx_queue->efx,
+ f->size, f->page, f->page_offset);
+ if (rc)
+ goto mem_err;
+ }
+
+ /* Start at new packet? */
+ if (state.packet_space == 0 &&
+ tso_start_new_packet(tx_queue, skb, &state) < 0)
+ goto mem_err;
+ }
+
+ /* Pass off to hardware */
+ falcon_push_buffers(tx_queue);
+
+ tx_queue->tso_bursts++;
+ return NETDEV_TX_OK;
+
+ mem_err:
+ EFX_ERR(tx_queue->efx, "Out of memory for TSO headers, or PCI mapping"
+ " error\n");
+ dev_kfree_skb_any((struct sk_buff *)skb);
+ goto unwind;
+
+ stop:
+ rc2 = NETDEV_TX_BUSY;
+
+ /* Stop the queue if it wasn't stopped before. */
+ if (tx_queue->stopped == 1)
+ efx_stop_queue(tx_queue->efx);
+
+ unwind:
+ efx_enqueue_unwind(tx_queue);
+ return rc2;
+}
+
+
+/*
+ * Free up all TSO datastructures associated with tx_queue. This
+ * routine should be called only once the tx_queue is both empty and
+ * will no longer be used.
+ */
+static void efx_fini_tso(struct efx_tx_queue *tx_queue)
+{
+ unsigned i;
+
+ if (tx_queue->buffer)
+ for (i = 0; i <= tx_queue->efx->type->txd_ring_mask; ++i)
+ efx_tsoh_free(tx_queue, &tx_queue->buffer[i]);
+
+ while (tx_queue->tso_headers_free != NULL)
+ efx_tsoh_block_free(tx_queue, tx_queue->tso_headers_free,
+ tx_queue->efx->pci_dev);
+}
diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h
new file mode 100644
index 000000000000..1526a73b4b51
--- /dev/null
+++ b/drivers/net/sfc/tx.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_TX_H
+#define EFX_TX_H
+
+#include "net_driver.h"
+
+int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
+int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
+
+int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
+void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
+
+#endif /* EFX_TX_H */
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
new file mode 100644
index 000000000000..dca62f190198
--- /dev/null
+++ b/drivers/net/sfc/workarounds.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_WORKAROUNDS_H
+#define EFX_WORKAROUNDS_H
+
+/*
+ * Hardware workarounds.
+ * Bug numbers are from Solarflare's Bugzilla.
+ */
+
+#define EFX_WORKAROUND_ALWAYS(efx) 1
+#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
+
+/* XAUI resets if link not detected */
+#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
+/* SNAP frames have TOBE_DISC set */
+#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
+/* RX PCIe double split performance issue */
+#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
+/* TX pkt parser problem with <= 16 byte TXes */
+#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
+/* XGXS and XAUI reset sequencing in SW */
+#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
+/* Low rate CRC errors require XAUI reset */
+#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
+/* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
+ * or a PCIe error (bug 11028) */
+#define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
+/* Transmit flow control may get disabled */
+#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
+/* Flush events can take a very long time to appear */
+#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
+
+/* Spurious parity errors in TSORT buffers */
+#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
+/* iSCSI parsing errors */
+#define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
+/* RX events go missing */
+#define EFX_WORKAROUND_5676 EFX_WORKAROUND_FALCON_A
+/* RX_RESET on A1 */
+#define EFX_WORKAROUND_6555 EFX_WORKAROUND_FALCON_A
+/* Increase filter depth to avoid RX_RESET */
+#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
+/* Flushes may never complete */
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+/* Leak overlength packets rather than free */
+#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
+
+#endif /* EFX_WORKAROUNDS_H */
diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h
new file mode 100644
index 000000000000..b0d1f225b70a
--- /dev/null
+++ b/drivers/net/sfc/xenpack.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_XENPACK_H
+#define EFX_XENPACK_H
+
+/* Exported functions from Xenpack standard PHY control */
+
+#include "mdio_10g.h"
+
+/****************************************************************************/
+/* XENPACK MDIO register extensions */
+#define MDIO_XP_LASI_RX_CTRL (0x9000)
+#define MDIO_XP_LASI_TX_CTRL (0x9001)
+#define MDIO_XP_LASI_CTRL (0x9002)
+#define MDIO_XP_LASI_RX_STAT (0x9003)
+#define MDIO_XP_LASI_TX_STAT (0x9004)
+#define MDIO_XP_LASI_STAT (0x9005)
+
+/* Control/Status bits */
+#define XP_LASI_LS_ALARM (1 << 0)
+#define XP_LASI_TX_ALARM (1 << 1)
+#define XP_LASI_RX_ALARM (1 << 2)
+/* These two are Quake vendor extensions to the standard XENPACK defines */
+#define XP_LASI_LS_INTB (1 << 3)
+#define XP_LASI_TEST (1 << 7)
+
+/* Enable LASI interrupts for PHY */
+static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
+{
+ int reg;
+ int phy_id = efx->mii.phy_id;
+ /* Read to clear LASI status register */
+ reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_STAT);
+
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
+}
+
+/* Read the LASI interrupt status to clear the interrupt. */
+static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
+{
+ /* Read to clear link status alarm */
+ return mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
+}
+
+/* Turn off LASI interrupts */
+static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
+{
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_CTRL, 0);
+}
+
+#endif /* EFX_XENPACK_H */
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
new file mode 100644
index 000000000000..3b9f9ddbc372
--- /dev/null
+++ b/drivers/net/sfc/xfp_phy.c
@@ -0,0 +1,168 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+/*
+ * Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
+ * See www.amcc.com for details (search for qt2032)
+ */
+
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include "efx.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "xenpack.h"
+#include "phy.h"
+#include "mac.h"
+
+#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS)
+
+#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \
+ (1 << LOOPBACK_PMAPMD) | \
+ (1 << LOOPBACK_NETWORK))
+
+/****************************************************************************/
+/* Quake-specific MDIO registers */
+#define MDIO_QUAKE_LED0_REG (0xD006)
+
+void xfp_set_led(struct efx_nic *p, int led, int mode)
+{
+ int addr = MDIO_QUAKE_LED0_REG + led;
+ mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
+ mode);
+}
+
+struct xfp_phy_data {
+ int tx_disabled;
+};
+
+#define XFP_MAX_RESET_TIME 500
+#define XFP_RESET_WAIT 10
+
+/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
+ * a complete soft reset.
+ */
+static int xfp_reset_phy(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
+ XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
+ XFP_RESET_WAIT);
+ if (rc < 0)
+ goto fail;
+
+ /* Wait 250ms for the PHY to complete bootup */
+ msleep(250);
+
+ /* Check that all the MMDs we expect are present and responding. We
+ * expect faults on some if the link is down, but not on the PHY XS */
+ rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
+ MDIO_MMDREG_DEVS0_PHYXS);
+ if (rc < 0)
+ goto fail;
+
+ efx->board_info.init_leds(efx);
+
+ return rc;
+
+ fail:
+ EFX_ERR(efx, "XFP: reset timed out!\n");
+ return rc;
+}
+
+static int xfp_phy_init(struct efx_nic *efx)
+{
+ struct xfp_phy_data *phy_data;
+ u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
+ int rc;
+
+ phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
+ efx->phy_data = (void *) phy_data;
+
+ EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
+ " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
+ MDIO_ID_REV(devid));
+
+ phy_data->tx_disabled = efx->tx_disabled;
+
+ rc = xfp_reset_phy(efx);
+
+ EFX_INFO(efx, "XFP: PHY init %s.\n",
+ rc ? "failed" : "successful");
+ if (rc < 0)
+ goto fail;
+
+ return 0;
+
+ fail:
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+ return rc;
+}
+
+static void xfp_phy_clear_interrupt(struct efx_nic *efx)
+{
+ xenpack_clear_lasi_irqs(efx);
+}
+
+static int xfp_link_ok(struct efx_nic *efx)
+{
+ return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
+}
+
+static int xfp_phy_check_hw(struct efx_nic *efx)
+{
+ int rc = 0;
+ int link_up = xfp_link_ok(efx);
+ /* Simulate a PHY event if link state has changed */
+ if (link_up != efx->link_up)
+ falcon_xmac_sim_phy_event(efx);
+
+ return rc;
+}
+
+static void xfp_phy_reconfigure(struct efx_nic *efx)
+{
+ struct xfp_phy_data *phy_data = efx->phy_data;
+
+ /* Reset the PHY when moving from tx off to tx on */
+ if (phy_data->tx_disabled && !efx->tx_disabled)
+ xfp_reset_phy(efx);
+
+ mdio_clause45_transmit_disable(efx);
+ mdio_clause45_phy_reconfigure(efx);
+
+ phy_data->tx_disabled = efx->tx_disabled;
+ efx->link_up = xfp_link_ok(efx);
+ efx->link_options = GM_LPA_10000FULL;
+}
+
+
+static void xfp_phy_fini(struct efx_nic *efx)
+{
+ /* Clobber the LED if it was blinking */
+ efx->board_info.blink(efx, 0);
+
+ /* Free the context block */
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+}
+
+struct efx_phy_operations falcon_xfp_phy_ops = {
+ .init = xfp_phy_init,
+ .reconfigure = xfp_phy_reconfigure,
+ .check_hw = xfp_phy_check_hw,
+ .fini = xfp_phy_fini,
+ .clear_interrupt = xfp_phy_clear_interrupt,
+ .reset_xaui = efx_port_dummy_op_void,
+ .mmds = XFP_REQUIRED_DEVS,
+ .loopbacks = XFP_LOOPBACKS,
+};
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 20745fd4e973..abc63b0663be 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -212,6 +212,12 @@ enum _DescStatusBit {
THOL2 = 0x20000000,
THOL1 = 0x10000000,
THOL0 = 0x00000000,
+
+ WND = 0x00080000,
+ TABRT = 0x00040000,
+ FIFO = 0x00020000,
+ LINK = 0x00010000,
+ ColCountMask = 0x0000ffff,
/* RxDesc.status */
IPON = 0x20000000,
TCPON = 0x10000000,
@@ -480,30 +486,23 @@ static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
desc->status = 0x0;
}
-static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
- struct RxDesc *desc, u32 rx_buf_sz)
+static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
+ struct RxDesc *desc)
{
+ u32 rx_buf_sz = tp->rx_buf_sz;
struct sk_buff *skb;
- dma_addr_t mapping;
- int ret = 0;
-
- skb = dev_alloc_skb(rx_buf_sz);
- if (!skb)
- goto err_out;
-
- *sk_buff = skb;
- mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
+ if (likely(skb)) {
+ dma_addr_t mapping;
- sis190_map_to_asic(desc, mapping, rx_buf_sz);
-out:
- return ret;
+ mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ sis190_map_to_asic(desc, mapping, rx_buf_sz);
+ } else
+ sis190_make_unusable_by_asic(desc);
-err_out:
- ret = -ENOMEM;
- sis190_make_unusable_by_asic(desc);
- goto out;
+ return skb;
}
static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
@@ -512,37 +511,41 @@ static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
u32 cur;
for (cur = start; cur < end; cur++) {
- int ret, i = cur % NUM_RX_DESC;
+ unsigned int i = cur % NUM_RX_DESC;
if (tp->Rx_skbuff[i])
continue;
- ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
- tp->RxDescRing + i, tp->rx_buf_sz);
- if (ret < 0)
+ tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i);
+
+ if (!tp->Rx_skbuff[i])
break;
}
return cur - start;
}
-static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
- struct RxDesc *desc, int rx_buf_sz)
+static bool sis190_try_rx_copy(struct sis190_private *tp,
+ struct sk_buff **sk_buff, int pkt_size,
+ dma_addr_t addr)
{
- int ret = -1;
+ struct sk_buff *skb;
+ bool done = false;
- if (pkt_size < rx_copybreak) {
- struct sk_buff *skb;
+ if (pkt_size >= rx_copybreak)
+ goto out;
- skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
- if (skb) {
- skb_reserve(skb, NET_IP_ALIGN);
- skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
- *sk_buff = skb;
- sis190_give_to_asic(desc, rx_buf_sz);
- ret = 0;
- }
- }
- return ret;
+ skb = netdev_alloc_skb(tp->dev, pkt_size + 2);
+ if (!skb)
+ goto out;
+
+ pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size,
+ PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, 2);
+ skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
+ *sk_buff = skb;
+ done = true;
+out:
+ return done;
}
static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
@@ -592,9 +595,9 @@ static int sis190_rx_interrupt(struct net_device *dev,
sis190_give_to_asic(desc, tp->rx_buf_sz);
else {
struct sk_buff *skb = tp->Rx_skbuff[entry];
+ dma_addr_t addr = le32_to_cpu(desc->addr);
int pkt_size = (status & RxSizeMask) - 4;
- void (*pci_action)(struct pci_dev *, dma_addr_t,
- size_t, int) = pci_dma_sync_single_for_device;
+ struct pci_dev *pdev = tp->pci_dev;
if (unlikely(pkt_size > tp->rx_buf_sz)) {
net_intr(tp, KERN_INFO
@@ -606,20 +609,18 @@ static int sis190_rx_interrupt(struct net_device *dev,
continue;
}
- pci_dma_sync_single_for_cpu(tp->pci_dev,
- le32_to_cpu(desc->addr), tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
- if (sis190_try_rx_copy(&skb, pkt_size, desc,
- tp->rx_buf_sz)) {
- pci_action = pci_unmap_single;
+ if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) {
+ pci_dma_sync_single_for_device(pdev, addr,
+ tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ sis190_give_to_asic(desc, tp->rx_buf_sz);
+ } else {
+ pci_unmap_single(pdev, addr, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
tp->Rx_skbuff[entry] = NULL;
sis190_make_unusable_by_asic(desc);
}
- pci_action(tp->pci_dev, le32_to_cpu(desc->addr),
- tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
@@ -658,9 +659,31 @@ static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
memset(desc, 0x00, sizeof(*desc));
}
+static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats)
+{
+#define TxErrMask (WND | TABRT | FIFO | LINK)
+
+ if (!unlikely(status & TxErrMask))
+ return 0;
+
+ if (status & WND)
+ stats->tx_window_errors++;
+ if (status & TABRT)
+ stats->tx_aborted_errors++;
+ if (status & FIFO)
+ stats->tx_fifo_errors++;
+ if (status & LINK)
+ stats->tx_carrier_errors++;
+
+ stats->tx_errors++;
+
+ return -1;
+}
+
static void sis190_tx_interrupt(struct net_device *dev,
struct sis190_private *tp, void __iomem *ioaddr)
{
+ struct net_device_stats *stats = &dev->stats;
u32 pending, dirty_tx = tp->dirty_tx;
/*
* It would not be needed if queueing was allowed to be enabled
@@ -675,15 +698,19 @@ static void sis190_tx_interrupt(struct net_device *dev,
for (; pending; pending--, dirty_tx++) {
unsigned int entry = dirty_tx % NUM_TX_DESC;
struct TxDesc *txd = tp->TxDescRing + entry;
+ u32 status = le32_to_cpu(txd->status);
struct sk_buff *skb;
- if (le32_to_cpu(txd->status) & OWNbit)
+ if (status & OWNbit)
break;
skb = tp->Tx_skbuff[entry];
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
+ if (likely(sis190_tx_pkt_err(status, stats) == 0)) {
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+ stats->collisions += ((status & ColCountMask) - 1);
+ }
sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
tp->Tx_skbuff[entry] = NULL;
@@ -904,10 +931,9 @@ static void sis190_phy_task(struct work_struct *work)
mod_timer(&tp->timer, jiffies + HZ/10);
} else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
BMSR_ANEGCOMPLETE)) {
- net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n",
- dev->name);
netif_carrier_off(dev);
- mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
+ net_link(tp, KERN_WARNING "%s: auto-negotiating...\n",
+ dev->name);
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
} else {
/* Rejoice ! */
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 7bb3ba9bcbd8..c0a5eea20007 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1966,13 +1966,13 @@ struct sky2_status_le {
struct tx_ring_info {
struct sk_buff *skb;
DECLARE_PCI_UNMAP_ADDR(mapaddr);
- DECLARE_PCI_UNMAP_ADDR(maplen);
+ DECLARE_PCI_UNMAP_LEN(maplen);
};
struct rx_ring_info {
struct sk_buff *skb;
dma_addr_t data_addr;
- DECLARE_PCI_UNMAP_ADDR(data_size);
+ DECLARE_PCI_UNMAP_LEN(data_size);
dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
};
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5a55ede352f4..84af68fdb6c2 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -396,14 +396,14 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
/* Order of next two lines is *very* important.
* When we are sending a little amount of data,
- * the transfer may be completed inside driver.write()
+ * the transfer may be completed inside the ops->write()
* routine, because it's running with interrupts enabled.
* In this case we *never* got WRITE_WAKEUP event,
* if we did not request it before write operation.
* 14 Oct 1994 Dmitry Gorodchanin.
*/
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
#ifdef SL_CHECK_TRANSMIT
sl->dev->trans_start = jiffies;
#endif
@@ -437,7 +437,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
return;
}
- actual = tty->driver->write(tty, sl->xhead, sl->xleft);
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
}
@@ -462,7 +462,7 @@ static void sl_tx_timeout(struct net_device *dev)
}
printk(KERN_WARNING "%s: transmit timed out, %s?\n",
dev->name,
- (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+ (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error");
sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@@ -830,6 +830,9 @@ static int slip_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
/* RTnetlink lock is misused here to serialize concurrent
opens of slip channels. There are better ways, but it is
the simplest one.
@@ -1432,7 +1435,7 @@ static void sl_outfill(unsigned long sls)
/* put END into tty queue. Is it right ??? */
if (!netif_queue_stopped(sl->dev)) {
/* if device busy no outfill */
- sl->tty->driver->write(sl->tty, &s, 1);
+ sl->tty->ops->write(sl->tty, &s, 1);
}
} else
set_bit(SLF_OUTWAIT, &sl->flags);
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index f8d46134daca..359452a06c67 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -250,6 +250,9 @@ struct net_device * __init sun3lance_probe(int unit)
static int found;
int err = -ENODEV;
+ if (!MACH_IS_SUN3 && !MACH_IS_SUN3X)
+ return ERR_PTR(-ENODEV);
+
/* check that this machine has an onboard lance */
switch(idprom->id_machtype) {
case SM_SUN3|SM_3_50:
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index e83b166aa6b9..432e837a1760 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -649,7 +649,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
}
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_SYS_RAWIO))
return -EPERM;
switch (data[0]) {
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e3f74c9f78bd..07b3f77e7626 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.91"
-#define DRV_MODULE_RELDATE "April 18, 2008"
+#define DRV_MODULE_VERSION "3.92"
+#define DRV_MODULE_RELDATE "May 2, 2008"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -1656,12 +1656,76 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
return 0;
}
+/* tp->lock is held. */
+static void tg3_wait_for_event_ack(struct tg3 *tp)
+{
+ int i;
+
+ /* Wait for up to 2.5 milliseconds */
+ for (i = 0; i < 250000; i++) {
+ if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
+ break;
+ udelay(10);
+ }
+}
+
+/* tp->lock is held. */
+static void tg3_ump_link_report(struct tg3 *tp)
+{
+ u32 reg;
+ u32 val;
+
+ if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ return;
+
+ tg3_wait_for_event_ack(tp);
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+
+ val = 0;
+ if (!tg3_readphy(tp, MII_BMCR, &reg))
+ val = reg << 16;
+ if (!tg3_readphy(tp, MII_BMSR, &reg))
+ val |= (reg & 0xffff);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
+
+ val = 0;
+ if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
+ val = reg << 16;
+ if (!tg3_readphy(tp, MII_LPA, &reg))
+ val |= (reg & 0xffff);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
+
+ val = 0;
+ if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
+ if (!tg3_readphy(tp, MII_CTRL1000, &reg))
+ val = reg << 16;
+ if (!tg3_readphy(tp, MII_STAT1000, &reg))
+ val |= (reg & 0xffff);
+ }
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+
+ if (!tg3_readphy(tp, MII_PHYADDR, &reg))
+ val = reg << 16;
+ else
+ val = 0;
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
+
+ val = tr32(GRC_RX_CPU_EVENT);
+ val |= GRC_RX_CPU_DRIVER_EVENT;
+ tw32_f(GRC_RX_CPU_EVENT, val);
+}
+
static void tg3_link_report(struct tg3 *tp)
{
if (!netif_carrier_ok(tp->dev)) {
if (netif_msg_link(tp))
printk(KERN_INFO PFX "%s: Link is down.\n",
tp->dev->name);
+ tg3_ump_link_report(tp);
} else if (netif_msg_link(tp)) {
printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
tp->dev->name,
@@ -1679,6 +1743,7 @@ static void tg3_link_report(struct tg3 *tp)
"on" : "off",
(tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
"on" : "off");
+ tg3_ump_link_report(tp);
}
}
@@ -2097,9 +2162,11 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
MAC_STATUS_LNKSTATE_CHANGED));
udelay(40);
- tp->mi_mode = MAC_MI_MODE_BASE;
- tw32_f(MAC_MI_MODE, tp->mi_mode);
- udelay(80);
+ if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+ tw32_f(MAC_MI_MODE,
+ (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+ udelay(80);
+ }
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
@@ -4361,7 +4428,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
}
segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
goto tg3_tso_bug_end;
do {
@@ -5498,19 +5565,17 @@ static void tg3_stop_fw(struct tg3 *tp)
if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
u32 val;
- int i;
+
+ /* Wait for RX cpu to ACK the previous event. */
+ tg3_wait_for_event_ack(tp);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
val = tr32(GRC_RX_CPU_EVENT);
- val |= (1 << 14);
+ val |= GRC_RX_CPU_DRIVER_EVENT;
tw32(GRC_RX_CPU_EVENT, val);
- /* Wait for RX cpu to ACK the event. */
- for (i = 0; i < 100; i++) {
- if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
- break;
- udelay(1);
- }
+ /* Wait for RX cpu to ACK this event. */
+ tg3_wait_for_event_ack(tp);
}
}
@@ -7102,7 +7167,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->link_config.autoneg = tp->link_config.orig_autoneg;
}
- tp->mi_mode = MAC_MI_MODE_BASE;
+ tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
@@ -7400,14 +7465,16 @@ static void tg3_timer(unsigned long __opaque)
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
+ tg3_wait_for_event_ack(tp);
+
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
FWCMD_NICDRV_ALIVE3);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */
tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
val = tr32(GRC_RX_CPU_EVENT);
- val |= (1 << 14);
- tw32(GRC_RX_CPU_EVENT, val);
+ val |= GRC_RX_CPU_DRIVER_EVENT;
+ tw32_f(GRC_RX_CPU_EVENT, val);
}
tp->asf_counter = tp->asf_multiplier;
}
@@ -9568,14 +9635,9 @@ static int tg3_test_loopback(struct tg3 *tp)
/* Turn off link-based power management. */
cpmuctrl = tr32(TG3_CPMU_CTRL);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX)
- tw32(TG3_CPMU_CTRL,
- cpmuctrl & ~(CPMU_CTRL_LINK_SPEED_MODE |
- CPMU_CTRL_LINK_AWARE_MODE));
- else
- tw32(TG3_CPMU_CTRL,
- cpmuctrl & ~CPMU_CTRL_LINK_AWARE_MODE);
+ tw32(TG3_CPMU_CTRL,
+ cpmuctrl & ~(CPMU_CTRL_LINK_SPEED_MODE |
+ CPMU_CTRL_LINK_AWARE_MODE));
}
if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
@@ -9892,7 +9954,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
return;
}
}
- tp->nvram_size = 0x80000;
+ tp->nvram_size = TG3_NVRAM_SIZE_512KB;
}
static void __devinit tg3_get_nvram_info(struct tg3 *tp)
@@ -10033,11 +10095,14 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
tp->nvram_pagesize = 264;
if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 ||
nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5)
- tp->nvram_size = (protect ? 0x3e200 : 0x80000);
+ tp->nvram_size = (protect ? 0x3e200 :
+ TG3_NVRAM_SIZE_512KB);
else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2)
- tp->nvram_size = (protect ? 0x1f200 : 0x40000);
+ tp->nvram_size = (protect ? 0x1f200 :
+ TG3_NVRAM_SIZE_256KB);
else
- tp->nvram_size = (protect ? 0x1f200 : 0x20000);
+ tp->nvram_size = (protect ? 0x1f200 :
+ TG3_NVRAM_SIZE_128KB);
break;
case FLASH_5752VENDOR_ST_M45PE10:
case FLASH_5752VENDOR_ST_M45PE20:
@@ -10047,11 +10112,17 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 256;
if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10)
- tp->nvram_size = (protect ? 0x10000 : 0x20000);
+ tp->nvram_size = (protect ?
+ TG3_NVRAM_SIZE_64KB :
+ TG3_NVRAM_SIZE_128KB);
else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20)
- tp->nvram_size = (protect ? 0x10000 : 0x40000);
+ tp->nvram_size = (protect ?
+ TG3_NVRAM_SIZE_64KB :
+ TG3_NVRAM_SIZE_256KB);
else
- tp->nvram_size = (protect ? 0x20000 : 0x80000);
+ tp->nvram_size = (protect ?
+ TG3_NVRAM_SIZE_128KB :
+ TG3_NVRAM_SIZE_512KB);
break;
}
}
@@ -10145,25 +10216,25 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
case FLASH_5761VENDOR_ATMEL_MDB161D:
case FLASH_5761VENDOR_ST_A_M45PE16:
case FLASH_5761VENDOR_ST_M_M45PE16:
- tp->nvram_size = 0x100000;
+ tp->nvram_size = TG3_NVRAM_SIZE_2MB;
break;
case FLASH_5761VENDOR_ATMEL_ADB081D:
case FLASH_5761VENDOR_ATMEL_MDB081D:
case FLASH_5761VENDOR_ST_A_M45PE80:
case FLASH_5761VENDOR_ST_M_M45PE80:
- tp->nvram_size = 0x80000;
+ tp->nvram_size = TG3_NVRAM_SIZE_1MB;
break;
case FLASH_5761VENDOR_ATMEL_ADB041D:
case FLASH_5761VENDOR_ATMEL_MDB041D:
case FLASH_5761VENDOR_ST_A_M45PE40:
case FLASH_5761VENDOR_ST_M_M45PE40:
- tp->nvram_size = 0x40000;
+ tp->nvram_size = TG3_NVRAM_SIZE_512KB;
break;
case FLASH_5761VENDOR_ATMEL_ADB021D:
case FLASH_5761VENDOR_ATMEL_MDB021D:
case FLASH_5761VENDOR_ST_A_M45PE20:
case FLASH_5761VENDOR_ST_M_M45PE20:
- tp->nvram_size = 0x20000;
+ tp->nvram_size = TG3_NVRAM_SIZE_256KB;
break;
}
}
@@ -11764,6 +11835,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->phy_otp = TG3_OTP_DEFAULT;
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
+ else
+ tp->mi_mode = MAC_MI_MODE_BASE;
+
tp->coalesce_mode = 0;
if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
@@ -12692,7 +12769,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tp->mac_mode = TG3_DEF_MAC_MODE;
tp->rx_mode = TG3_DEF_RX_MODE;
tp->tx_mode = TG3_DEF_TX_MODE;
- tp->mi_mode = MAC_MI_MODE_BASE;
+
if (tg3_debug > 0)
tp->msg_enable = tg3_debug;
else
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index c688c3ac5035..0404f93baa29 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -415,7 +415,7 @@
#define MAC_MI_MODE_CLK_10MHZ 0x00000001
#define MAC_MI_MODE_SHORT_PREAMBLE 0x00000002
#define MAC_MI_MODE_AUTO_POLL 0x00000010
-#define MAC_MI_MODE_CORE_CLK_62MHZ 0x00008000
+#define MAC_MI_MODE_500KHZ_CONST 0x00008000
#define MAC_MI_MODE_BASE 0x000c0000 /* XXX magic values XXX */
#define MAC_AUTO_POLL_STATUS 0x00000458
#define MAC_AUTO_POLL_ERROR 0x00000001
@@ -1429,6 +1429,7 @@
#define GRC_LCLCTRL_AUTO_SEEPROM 0x01000000
#define GRC_TIMER 0x0000680c
#define GRC_RX_CPU_EVENT 0x00006810
+#define GRC_RX_CPU_DRIVER_EVENT 0x00004000
#define GRC_RX_TIMER_REF 0x00006814
#define GRC_RX_CPU_SEM 0x00006818
#define GRC_REMOTE_RX_CPU_ATTN 0x0000681c
@@ -1676,6 +1677,7 @@
#define FWCMD_NICDRV_IPV6ADDR_CHG 0x00000004
#define FWCMD_NICDRV_FIX_DMAR 0x00000005
#define FWCMD_NICDRV_FIX_DMAW 0x00000006
+#define FWCMD_NICDRV_LINK_UPDATE 0x0000000c
#define FWCMD_NICDRV_ALIVE2 0x0000000d
#define FWCMD_NICDRV_ALIVE3 0x0000000e
#define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c
@@ -2576,6 +2578,13 @@ struct tg3 {
int nvram_lock_cnt;
u32 nvram_size;
+#define TG3_NVRAM_SIZE_64KB 0x00010000
+#define TG3_NVRAM_SIZE_128KB 0x00020000
+#define TG3_NVRAM_SIZE_256KB 0x00040000
+#define TG3_NVRAM_SIZE_512KB 0x00080000
+#define TG3_NVRAM_SIZE_1MB 0x00100000
+#define TG3_NVRAM_SIZE_2MB 0x00200000
+
u32 nvram_pagesize;
u32 nvram_jedecnum;
@@ -2584,10 +2593,10 @@ struct tg3 {
#define JEDEC_SAIFUN 0x4f
#define JEDEC_SST 0xbf
-#define ATMEL_AT24C64_CHIP_SIZE (64 * 1024)
+#define ATMEL_AT24C64_CHIP_SIZE TG3_NVRAM_SIZE_64KB
#define ATMEL_AT24C64_PAGE_SIZE (32)
-#define ATMEL_AT24C512_CHIP_SIZE (512 * 1024)
+#define ATMEL_AT24C512_CHIP_SIZE TG3_NVRAM_SIZE_512KB
#define ATMEL_AT24C512_PAGE_SIZE (128)
#define ATMEL_AT45DB0X1B_PAGE_POS 9
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 6c6fc325c8f9..bc30c6e8fea2 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -482,7 +482,6 @@
static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
#define c_char const char
-#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a)))
/*
** MII Information
@@ -4405,7 +4404,7 @@ srom_infoleaf_info(struct net_device *dev)
}
}
- lp->infoleaf_offset = TWIDDLE(p+1);
+ lp->infoleaf_offset = get_unaligned_le16(p + 1);
return 0;
}
@@ -4476,7 +4475,7 @@ srom_exec(struct net_device *dev, u_char *p)
while (count--) {
gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
- *p++ : TWIDDLE(w++)), dev);
+ *p++ : get_unaligned_le16(w++)), dev);
mdelay(2); /* 2ms per action */
}
@@ -4711,10 +4710,10 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : NULL); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : NULL); p += (*p + 1);
- lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
- lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ttm = TWIDDLE(p);
+ lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ttm = get_unaligned_le16(p);
return 0;
} else if ((lp->media == INIT) && (lp->timeout < 0)) {
lp->ibn = 1;
@@ -4751,16 +4750,16 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->infoblock_media = (*p) & MEDIA_CODE;
if ((*p++) & EXT_FIELD) {
- lp->cache.csr13 = TWIDDLE(p); p += 2;
- lp->cache.csr14 = TWIDDLE(p); p += 2;
- lp->cache.csr15 = TWIDDLE(p); p += 2;
+ lp->cache.csr13 = get_unaligned_le16(p); p += 2;
+ lp->cache.csr14 = get_unaligned_le16(p); p += 2;
+ lp->cache.csr15 = get_unaligned_le16(p); p += 2;
} else {
lp->cache.csr13 = CSR13;
lp->cache.csr14 = CSR14;
lp->cache.csr15 = CSR15;
}
- lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
- lp->cache.gep = ((s32)(TWIDDLE(p)) << 16);
+ lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2;
+ lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16);
lp->infoblock_csr6 = OMR_SIA;
lp->useMII = false;
@@ -4792,10 +4791,10 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p)
if (MOTO_SROM_BUG) lp->active = 0;
lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1);
lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1);
- lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
- lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ttm = get_unaligned_le16(p); p += 2;
lp->phy[lp->active].mci = *p;
return 0;
} else if ((lp->media == INIT) && (lp->timeout < 0)) {
@@ -4835,8 +4834,8 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->cache.csr13 = CSR13; /* Hard coded defaults */
lp->cache.csr14 = CSR14;
lp->cache.csr15 = CSR15;
- lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
- lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2;
+ lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2;
+ lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); p += 2;
csr6 = *p++;
flags = *p++;
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h
index 9fb8d7f07994..f5f33b3eb067 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/tulip/de4x5.h
@@ -1017,4 +1017,4 @@ struct de4x5_ioctl {
#define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */
#define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */
-#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG (lp->active == 8 && (get_unaligned_le32(dev->dev_addr) & 0x00ffffff) == 0x3e0008)
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 908422f2f320..92c68a22f16b 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/unaligned.h>
@@ -304,11 +305,7 @@ enum t21143_csr6_bits {
#define RUN_AT(x) (jiffies + (x))
-#if defined(__i386__) /* AKA get_unaligned() */
-#define get_u16(ptr) (*(u16 *)(ptr))
-#else
-#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
-#endif
+#define get_u16(ptr) get_unaligned_le16((ptr))
struct medialeaf {
u8 type;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index fa1c1c329a2d..f9d13fa05d64 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -327,8 +327,8 @@ static void tulip_up(struct net_device *dev)
tp->dirty_rx = tp->dirty_tx = 0;
if (tp->flags & MC_HASH_ONLY) {
- u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr));
- u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4)));
+ u32 addr_low = get_unaligned_le32(dev->dev_addr);
+ u32 addr_high = get_unaligned_le16(dev->dev_addr + 4);
if (tp->chip_id == AX88140) {
iowrite32(0, ioaddr + CSR13);
iowrite32(addr_low, ioaddr + CSR14);
@@ -1437,13 +1437,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
do
value = ioread32(ioaddr + CSR9);
while (value < 0 && --boguscnt > 0);
- put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i);
+ put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i);
sum += value & 0xffff;
}
} else if (chip_idx == COMET) {
/* No need to read the EEPROM. */
- put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr);
- put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4));
+ put_unaligned_le32(ioread32(ioaddr + 0xA4), dev->dev_addr);
+ put_unaligned_le16(ioread32(ioaddr + 0xA8), dev->dev_addr + 4);
for (i = 0; i < 6; i ++)
sum += dev->dev_addr[i];
} else {
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index a59c1f224aa8..2511ca7a12aa 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -434,10 +434,6 @@ static int uli526x_open(struct net_device *dev)
ULI526X_DBUG(0, "uli526x_open", 0);
- ret = request_irq(dev->irq, &uli526x_interrupt, IRQF_SHARED, dev->name, dev);
- if (ret)
- return ret;
-
/* system variable init */
db->cr6_data = CR6_DEFAULT | uli526x_cr6_user_set;
db->tx_packet_cnt = 0;
@@ -456,6 +452,10 @@ static int uli526x_open(struct net_device *dev)
/* Initialize ULI526X board */
uli526x_init(dev);
+ ret = request_irq(dev->irq, &uli526x_interrupt, IRQF_SHARED, dev->name, dev);
+ if (ret)
+ return ret;
+
/* Active System Interface */
netif_wake_queue(dev);
@@ -1368,6 +1368,12 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
* This setup frame initialize ULI526X address filter mode
*/
+#ifdef __BIG_ENDIAN
+#define FLT_SHIFT 16
+#else
+#define FLT_SHIFT 0
+#endif
+
static void send_filter_frame(struct net_device *dev, int mc_cnt)
{
struct uli526x_board_info *db = netdev_priv(dev);
@@ -1384,27 +1390,27 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
/* Node address */
addrptr = (u16 *) dev->dev_addr;
- *suptr++ = addrptr[0];
- *suptr++ = addrptr[1];
- *suptr++ = addrptr[2];
+ *suptr++ = addrptr[0] << FLT_SHIFT;
+ *suptr++ = addrptr[1] << FLT_SHIFT;
+ *suptr++ = addrptr[2] << FLT_SHIFT;
/* broadcast address */
- *suptr++ = 0xffff;
- *suptr++ = 0xffff;
- *suptr++ = 0xffff;
+ *suptr++ = 0xffff << FLT_SHIFT;
+ *suptr++ = 0xffff << FLT_SHIFT;
+ *suptr++ = 0xffff << FLT_SHIFT;
/* fit the multicast address */
for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
addrptr = (u16 *) mcptr->dmi_addr;
- *suptr++ = addrptr[0];
- *suptr++ = addrptr[1];
- *suptr++ = addrptr[2];
+ *suptr++ = addrptr[0] << FLT_SHIFT;
+ *suptr++ = addrptr[1] << FLT_SHIFT;
+ *suptr++ = addrptr[2] << FLT_SHIFT;
}
for (; i<14; i++) {
- *suptr++ = 0xffff;
- *suptr++ = 0xffff;
- *suptr++ = 0xffff;
+ *suptr++ = 0xffff << FLT_SHIFT;
+ *suptr++ = 0xffff << FLT_SHIFT;
+ *suptr++ = 0xffff << FLT_SHIFT;
}
/* prepare the setup frame */
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 281ce3d39532..ca0bdac07a78 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -62,7 +62,6 @@
#endif /* UGETH_VERBOSE_DEBUG */
#define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1
-void uec_set_ethtool_ops(struct net_device *netdev);
static DEFINE_SPINLOCK(ugeth_lock);
@@ -216,7 +215,8 @@ static struct list_head *dequeue(struct list_head *lh)
}
}
-static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
+static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
+ u8 __iomem *bd)
{
struct sk_buff *skb = NULL;
@@ -236,21 +236,22 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
skb->dev = ugeth->dev;
- out_be32(&((struct qe_bd *)bd)->buf,
+ out_be32(&((struct qe_bd __iomem *)bd)->buf,
dma_map_single(NULL,
skb->data,
ugeth->ug_info->uf_info.max_rx_buf_length +
UCC_GETH_RX_DATA_BUF_ALIGNMENT,
DMA_FROM_DEVICE));
- out_be32((u32 *)bd, (R_E | R_I | (in_be32((u32 *)bd) & R_W)));
+ out_be32((u32 __iomem *)bd,
+ (R_E | R_I | (in_be32((u32 __iomem*)bd) & R_W)));
return skb;
}
static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ)
{
- u8 *bd;
+ u8 __iomem *bd;
u32 bd_status;
struct sk_buff *skb;
int i;
@@ -259,7 +260,7 @@ static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ)
i = 0;
do {
- bd_status = in_be32((u32*)bd);
+ bd_status = in_be32((u32 __iomem *)bd);
skb = get_new_skb(ugeth, bd);
if (!skb) /* If can not allocate data buffer,
@@ -277,7 +278,7 @@ static int rx_bd_buffer_set(struct ucc_geth_private *ugeth, u8 rxQ)
}
static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
- volatile u32 *p_start,
+ u32 *p_start,
u8 num_entries,
u32 thread_size,
u32 thread_alignment,
@@ -316,7 +317,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
}
static int return_init_enet_entries(struct ucc_geth_private *ugeth,
- volatile u32 *p_start,
+ u32 *p_start,
u8 num_entries,
enum qe_risc_allocation risc,
int skip_page_for_first_entry)
@@ -326,21 +327,22 @@ static int return_init_enet_entries(struct ucc_geth_private *ugeth,
int snum;
for (i = 0; i < num_entries; i++) {
+ u32 val = *p_start;
+
/* Check that this entry was actually valid --
needed in case failed in allocations */
- if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) {
+ if ((val & ENET_INIT_PARAM_RISC_MASK) == risc) {
snum =
- (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >>
+ (u32) (val & ENET_INIT_PARAM_SNUM_MASK) >>
ENET_INIT_PARAM_SNUM_SHIFT;
qe_put_snum((u8) snum);
if (!((i == 0) && skip_page_for_first_entry)) {
/* First entry of Rx does not have page */
init_enet_offset =
- (in_be32(p_start) &
- ENET_INIT_PARAM_PTR_MASK);
+ (val & ENET_INIT_PARAM_PTR_MASK);
qe_muram_free(init_enet_offset);
}
- *(p_start++) = 0; /* Just for cosmetics */
+ *p_start++ = 0;
}
}
@@ -349,7 +351,7 @@ static int return_init_enet_entries(struct ucc_geth_private *ugeth,
#ifdef DEBUG
static int dump_init_enet_entries(struct ucc_geth_private *ugeth,
- volatile u32 *p_start,
+ u32 __iomem *p_start,
u8 num_entries,
u32 thread_size,
enum qe_risc_allocation risc,
@@ -360,11 +362,13 @@ static int dump_init_enet_entries(struct ucc_geth_private *ugeth,
int snum;
for (i = 0; i < num_entries; i++) {
+ u32 val = in_be32(p_start);
+
/* Check that this entry was actually valid --
needed in case failed in allocations */
- if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) {
+ if ((val & ENET_INIT_PARAM_RISC_MASK) == risc) {
snum =
- (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >>
+ (u32) (val & ENET_INIT_PARAM_SNUM_MASK) >>
ENET_INIT_PARAM_SNUM_SHIFT;
qe_put_snum((u8) snum);
if (!((i == 0) && skip_page_for_first_entry)) {
@@ -440,7 +444,7 @@ static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth,
static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
if (!(paddr_num < NUM_OF_PADDRS)) {
ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
@@ -448,7 +452,7 @@ static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
}
p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->p_rx_glbl_pram->
addressfiltering;
/* Writing address ff.ff.ff.ff.ff.ff disables address
@@ -463,11 +467,11 @@ static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
u8 *p_enet_addr)
{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
u32 cecr_subblock;
p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
+ (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->p_rx_glbl_pram->
addressfiltering;
cecr_subblock =
@@ -487,7 +491,7 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
static void magic_packet_detection_enable(struct ucc_geth_private *ugeth)
{
struct ucc_fast_private *uccf;
- struct ucc_geth *ug_regs;
+ struct ucc_geth __iomem *ug_regs;
u32 maccfg2, uccm;
uccf = ugeth->uccf;
@@ -507,7 +511,7 @@ static void magic_packet_detection_enable(struct ucc_geth_private *ugeth)
static void magic_packet_detection_disable(struct ucc_geth_private *ugeth)
{
struct ucc_fast_private *uccf;
- struct ucc_geth *ug_regs;
+ struct ucc_geth __iomem *ug_regs;
u32 maccfg2, uccm;
uccf = ugeth->uccf;
@@ -538,13 +542,13 @@ static void get_statistics(struct ucc_geth_private *ugeth,
rx_firmware_statistics,
struct ucc_geth_hardware_statistics *hardware_statistics)
{
- struct ucc_fast *uf_regs;
- struct ucc_geth *ug_regs;
+ struct ucc_fast __iomem *uf_regs;
+ struct ucc_geth __iomem *ug_regs;
struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram;
struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram;
ug_regs = ugeth->ug_regs;
- uf_regs = (struct ucc_fast *) ug_regs;
+ uf_regs = (struct ucc_fast __iomem *) ug_regs;
p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram;
p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram;
@@ -1132,9 +1136,9 @@ static void dump_regs(struct ucc_geth_private *ugeth)
}
#endif /* DEBUG */
-static void init_default_reg_vals(volatile u32 *upsmr_register,
- volatile u32 *maccfg1_register,
- volatile u32 *maccfg2_register)
+static void init_default_reg_vals(u32 __iomem *upsmr_register,
+ u32 __iomem *maccfg1_register,
+ u32 __iomem *maccfg2_register)
{
out_be32(upsmr_register, UCC_GETH_UPSMR_INIT);
out_be32(maccfg1_register, UCC_GETH_MACCFG1_INIT);
@@ -1148,7 +1152,7 @@ static int init_half_duplex_params(int alt_beb,
u8 alt_beb_truncation,
u8 max_retransmissions,
u8 collision_window,
- volatile u32 *hafdup_register)
+ u32 __iomem *hafdup_register)
{
u32 value = 0;
@@ -1180,7 +1184,7 @@ static int init_inter_frame_gap_params(u8 non_btb_cs_ipg,
u8 non_btb_ipg,
u8 min_ifg,
u8 btb_ipg,
- volatile u32 *ipgifg_register)
+ u32 __iomem *ipgifg_register)
{
u32 value = 0;
@@ -1215,9 +1219,9 @@ int init_flow_control_params(u32 automatic_flow_control_mode,
int tx_flow_control_enable,
u16 pause_period,
u16 extension_field,
- volatile u32 *upsmr_register,
- volatile u32 *uempr_register,
- volatile u32 *maccfg1_register)
+ u32 __iomem *upsmr_register,
+ u32 __iomem *uempr_register,
+ u32 __iomem *maccfg1_register)
{
u32 value = 0;
@@ -1243,8 +1247,8 @@ int init_flow_control_params(u32 automatic_flow_control_mode,
static int init_hw_statistics_gathering_mode(int enable_hardware_statistics,
int auto_zero_hardware_statistics,
- volatile u32 *upsmr_register,
- volatile u16 *uescr_register)
+ u32 __iomem *upsmr_register,
+ u16 __iomem *uescr_register)
{
u32 upsmr_value = 0;
u16 uescr_value = 0;
@@ -1270,12 +1274,12 @@ static int init_hw_statistics_gathering_mode(int enable_hardware_statistics,
static int init_firmware_statistics_gathering_mode(int
enable_tx_firmware_statistics,
int enable_rx_firmware_statistics,
- volatile u32 *tx_rmon_base_ptr,
+ u32 __iomem *tx_rmon_base_ptr,
u32 tx_firmware_statistics_structure_address,
- volatile u32 *rx_rmon_base_ptr,
+ u32 __iomem *rx_rmon_base_ptr,
u32 rx_firmware_statistics_structure_address,
- volatile u16 *temoder_register,
- volatile u32 *remoder_register)
+ u16 __iomem *temoder_register,
+ u32 __iomem *remoder_register)
{
/* Note: this function does not check if */
/* the parameters it receives are NULL */
@@ -1307,8 +1311,8 @@ static int init_mac_station_addr_regs(u8 address_byte_0,
u8 address_byte_3,
u8 address_byte_4,
u8 address_byte_5,
- volatile u32 *macstnaddr1_register,
- volatile u32 *macstnaddr2_register)
+ u32 __iomem *macstnaddr1_register,
+ u32 __iomem *macstnaddr2_register)
{
u32 value = 0;
@@ -1344,7 +1348,7 @@ static int init_mac_station_addr_regs(u8 address_byte_0,
}
static int init_check_frame_length_mode(int length_check,
- volatile u32 *maccfg2_register)
+ u32 __iomem *maccfg2_register)
{
u32 value = 0;
@@ -1360,7 +1364,7 @@ static int init_check_frame_length_mode(int length_check,
}
static int init_preamble_length(u8 preamble_length,
- volatile u32 *maccfg2_register)
+ u32 __iomem *maccfg2_register)
{
u32 value = 0;
@@ -1376,7 +1380,7 @@ static int init_preamble_length(u8 preamble_length,
static int init_rx_parameters(int reject_broadcast,
int receive_short_frames,
- int promiscuous, volatile u32 *upsmr_register)
+ int promiscuous, u32 __iomem *upsmr_register)
{
u32 value = 0;
@@ -1403,7 +1407,7 @@ static int init_rx_parameters(int reject_broadcast,
}
static int init_max_rx_buff_len(u16 max_rx_buf_len,
- volatile u16 *mrblr_register)
+ u16 __iomem *mrblr_register)
{
/* max_rx_buf_len value must be a multiple of 128 */
if ((max_rx_buf_len == 0)
@@ -1415,8 +1419,8 @@ static int init_max_rx_buff_len(u16 max_rx_buf_len,
}
static int init_min_frame_len(u16 min_frame_length,
- volatile u16 *minflr_register,
- volatile u16 *mrblr_register)
+ u16 __iomem *minflr_register,
+ u16 __iomem *mrblr_register)
{
u16 mrblr_value = 0;
@@ -1431,8 +1435,8 @@ static int init_min_frame_len(u16 min_frame_length,
static int adjust_enet_interface(struct ucc_geth_private *ugeth)
{
struct ucc_geth_info *ug_info;
- struct ucc_geth *ug_regs;
- struct ucc_fast *uf_regs;
+ struct ucc_geth __iomem *ug_regs;
+ struct ucc_fast __iomem *uf_regs;
int ret_val;
u32 upsmr, maccfg2, tbiBaseAddress;
u16 value;
@@ -1517,8 +1521,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
static void adjust_link(struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct ucc_geth *ug_regs;
- struct ucc_fast *uf_regs;
+ struct ucc_geth __iomem *ug_regs;
+ struct ucc_fast __iomem *uf_regs;
struct phy_device *phydev = ugeth->phydev;
unsigned long flags;
int new_state = 0;
@@ -1678,9 +1682,9 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
uccf = ugeth->uccf;
/* Clear acknowledge bit */
- temp = ugeth->p_rx_glbl_pram->rxgstpack;
+ temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack);
temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX;
- ugeth->p_rx_glbl_pram->rxgstpack = temp;
+ out_8(&ugeth->p_rx_glbl_pram->rxgstpack, temp);
/* Keep issuing command and checking acknowledge bit until
it is asserted, according to spec */
@@ -1692,7 +1696,7 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
QE_CR_PROTOCOL_ETHERNET, 0);
- temp = ugeth->p_rx_glbl_pram->rxgstpack;
+ temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack);
} while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
uccf->stopped_rx = 1;
@@ -1991,19 +1995,20 @@ static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private *
enum enet_addr_type
enet_addr_type)
{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
struct ucc_fast_private *uccf;
enum comm_dir comm_dir;
struct list_head *p_lh;
u16 i, num;
- u32 *addr_h, *addr_l;
+ u32 __iomem *addr_h;
+ u32 __iomem *addr_l;
u8 *p_counter;
uccf = ugeth->uccf;
p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
- addressfiltering;
+ (struct ucc_geth_82xx_address_filtering_pram __iomem *)
+ ugeth->p_rx_glbl_pram->addressfiltering;
if (enet_addr_type == ENET_ADDR_TYPE_GROUP) {
addr_h = &(p_82xx_addr_filt->gaddr_h);
@@ -2079,7 +2084,7 @@ static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *uge
static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
{
u16 i, j;
- u8 *bd;
+ u8 __iomem *bd;
if (!ugeth)
return;
@@ -2154,8 +2159,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
if (ugeth->tx_skbuff[i][j]) {
dma_unmap_single(NULL,
- ((struct qe_bd *)bd)->buf,
- (in_be32((u32 *)bd) &
+ in_be32(&((struct qe_bd __iomem *)bd)->buf),
+ (in_be32((u32 __iomem *)bd) &
BD_LENGTH_MASK),
DMA_TO_DEVICE);
dev_kfree_skb_any(ugeth->tx_skbuff[i][j]);
@@ -2182,7 +2187,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
if (ugeth->rx_skbuff[i][j]) {
dma_unmap_single(NULL,
- ((struct qe_bd *)bd)->buf,
+ in_be32(&((struct qe_bd __iomem *)bd)->buf),
ugeth->ug_info->
uf_info.max_rx_buf_length +
UCC_GETH_RX_DATA_BUF_ALIGNMENT,
@@ -2218,8 +2223,8 @@ static void ucc_geth_set_multi(struct net_device *dev)
{
struct ucc_geth_private *ugeth;
struct dev_mc_list *dmi;
- struct ucc_fast *uf_regs;
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ struct ucc_fast __iomem *uf_regs;
+ struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
int i;
ugeth = netdev_priv(dev);
@@ -2228,14 +2233,14 @@ static void ucc_geth_set_multi(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
- uf_regs->upsmr |= UPSMR_PRO;
+ out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr) | UPSMR_PRO);
} else {
- uf_regs->upsmr &= ~UPSMR_PRO;
+ out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr)&~UPSMR_PRO);
p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->
+ (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->
p_rx_glbl_pram->addressfiltering;
if (dev->flags & IFF_ALLMULTI) {
@@ -2270,7 +2275,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
static void ucc_geth_stop(struct ucc_geth_private *ugeth)
{
- struct ucc_geth *ug_regs = ugeth->ug_regs;
+ struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
struct phy_device *phydev = ugeth->phydev;
u32 tempval;
@@ -2419,20 +2424,20 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
- ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+ ugeth->ug_regs = (struct ucc_geth __iomem *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
return 0;
}
static int ucc_geth_startup(struct ucc_geth_private *ugeth)
{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
- struct ucc_geth_init_pram *p_init_enet_pram;
+ struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
+ struct ucc_geth_init_pram __iomem *p_init_enet_pram;
struct ucc_fast_private *uccf;
struct ucc_geth_info *ug_info;
struct ucc_fast_info *uf_info;
- struct ucc_fast *uf_regs;
- struct ucc_geth *ug_regs;
+ struct ucc_fast __iomem *uf_regs;
+ struct ucc_geth __iomem *ug_regs;
int ret_val = -EINVAL;
u32 remoder = UCC_GETH_REMODER_INIT;
u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
@@ -2440,7 +2445,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
u16 temoder = UCC_GETH_TEMODER_INIT;
u16 test;
u8 function_code = 0;
- u8 *bd, *endOfRing;
+ u8 __iomem *bd;
+ u8 __iomem *endOfRing;
u8 numThreadsRxNumerical, numThreadsTxNumerical;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -2602,11 +2608,11 @@ 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] =
- kmalloc((u32) (length + align), GFP_KERNEL);
+ (u32) 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] +
+ (u8 __iomem *)((ugeth->tx_bd_ring_offset[j] +
align) & ~(align - 1));
} else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
ugeth->tx_bd_ring_offset[j] =
@@ -2614,7 +2620,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_TX_BD_RING_ALIGNMENT);
if (!IS_ERR_VALUE(ugeth->tx_bd_ring_offset[j]))
ugeth->p_tx_bd_ring[j] =
- (u8 *) qe_muram_addr(ugeth->
+ (u8 __iomem *) qe_muram_addr(ugeth->
tx_bd_ring_offset[j]);
}
if (!ugeth->p_tx_bd_ring[j]) {
@@ -2626,8 +2632,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
/* Zero unused end of bd ring, according to spec */
- memset(ugeth->p_tx_bd_ring[j] +
- ug_info->bdRingLenTx[j] * sizeof(struct qe_bd), 0,
+ memset_io((void __iomem *)(ugeth->p_tx_bd_ring[j] +
+ ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)), 0,
length - ug_info->bdRingLenTx[j] * sizeof(struct qe_bd));
}
@@ -2639,10 +2645,10 @@ 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] =
- kmalloc((u32) (length + align), GFP_KERNEL);
+ (u32) 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] +
+ (u8 __iomem *)((ugeth->rx_bd_ring_offset[j] +
align) & ~(align - 1));
} else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
ugeth->rx_bd_ring_offset[j] =
@@ -2650,7 +2656,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_RX_BD_RING_ALIGNMENT);
if (!IS_ERR_VALUE(ugeth->rx_bd_ring_offset[j]))
ugeth->p_rx_bd_ring[j] =
- (u8 *) qe_muram_addr(ugeth->
+ (u8 __iomem *) qe_muram_addr(ugeth->
rx_bd_ring_offset[j]);
}
if (!ugeth->p_rx_bd_ring[j]) {
@@ -2685,14 +2691,14 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j];
for (i = 0; i < ug_info->bdRingLenTx[j]; i++) {
/* clear bd buffer */
- out_be32(&((struct qe_bd *)bd)->buf, 0);
+ out_be32(&((struct qe_bd __iomem *)bd)->buf, 0);
/* set bd status and length */
- out_be32((u32 *)bd, 0);
+ out_be32((u32 __iomem *)bd, 0);
bd += sizeof(struct qe_bd);
}
bd -= sizeof(struct qe_bd);
/* set bd status and length */
- out_be32((u32 *)bd, T_W); /* for last BD set Wrap bit */
+ out_be32((u32 __iomem *)bd, T_W); /* for last BD set Wrap bit */
}
/* Init Rx bds */
@@ -2717,14 +2723,14 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j];
for (i = 0; i < ug_info->bdRingLenRx[j]; i++) {
/* set bd status and length */
- out_be32((u32 *)bd, R_I);
+ out_be32((u32 __iomem *)bd, R_I);
/* clear bd buffer */
- out_be32(&((struct qe_bd *)bd)->buf, 0);
+ out_be32(&((struct qe_bd __iomem *)bd)->buf, 0);
bd += sizeof(struct qe_bd);
}
bd -= sizeof(struct qe_bd);
/* set bd status and length */
- out_be32((u32 *)bd, R_W); /* for last BD set Wrap bit */
+ out_be32((u32 __iomem *)bd, R_W); /* for last BD set Wrap bit */
}
/*
@@ -2744,10 +2750,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
ugeth->p_tx_glbl_pram =
- (struct ucc_geth_tx_global_pram *) qe_muram_addr(ugeth->
+ (struct ucc_geth_tx_global_pram __iomem *) qe_muram_addr(ugeth->
tx_glbl_pram_offset);
/* Zero out p_tx_glbl_pram */
- memset(ugeth->p_tx_glbl_pram, 0, sizeof(struct ucc_geth_tx_global_pram));
+ memset_io((void __iomem *)ugeth->p_tx_glbl_pram, 0, sizeof(struct ucc_geth_tx_global_pram));
/* Fill global PRAM */
@@ -2768,7 +2774,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_thread_data_tx =
- (struct ucc_geth_thread_data_tx *) qe_muram_addr(ugeth->
+ (struct ucc_geth_thread_data_tx __iomem *) qe_muram_addr(ugeth->
thread_dat_tx_offset);
out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset);
@@ -2779,7 +2785,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* iphoffset */
for (i = 0; i < TX_IP_OFFSET_ENTRY_MAX; i++)
- ugeth->p_tx_glbl_pram->iphoffset[i] = ug_info->iphoffset[i];
+ out_8(&ugeth->p_tx_glbl_pram->iphoffset[i],
+ ug_info->iphoffset[i]);
/* SQPTR */
/* Size varies with number of Tx queues */
@@ -2797,7 +2804,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_send_q_mem_reg =
- (struct ucc_geth_send_queue_mem_region *) qe_muram_addr(ugeth->
+ (struct ucc_geth_send_queue_mem_region __iomem *) qe_muram_addr(ugeth->
send_q_mem_reg_offset);
out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset);
@@ -2841,25 +2848,26 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_scheduler =
- (struct ucc_geth_scheduler *) qe_muram_addr(ugeth->
+ (struct ucc_geth_scheduler __iomem *) qe_muram_addr(ugeth->
scheduler_offset);
out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer,
ugeth->scheduler_offset);
/* Zero out p_scheduler */
- memset(ugeth->p_scheduler, 0, sizeof(struct ucc_geth_scheduler));
+ memset_io((void __iomem *)ugeth->p_scheduler, 0, sizeof(struct ucc_geth_scheduler));
/* Set values in scheduler */
out_be32(&ugeth->p_scheduler->mblinterval,
ug_info->mblinterval);
out_be16(&ugeth->p_scheduler->nortsrbytetime,
ug_info->nortsrbytetime);
- ugeth->p_scheduler->fracsiz = ug_info->fracsiz;
- ugeth->p_scheduler->strictpriorityq = ug_info->strictpriorityq;
- ugeth->p_scheduler->txasap = ug_info->txasap;
- ugeth->p_scheduler->extrabw = ug_info->extrabw;
+ out_8(&ugeth->p_scheduler->fracsiz, ug_info->fracsiz);
+ out_8(&ugeth->p_scheduler->strictpriorityq,
+ ug_info->strictpriorityq);
+ out_8(&ugeth->p_scheduler->txasap, ug_info->txasap);
+ out_8(&ugeth->p_scheduler->extrabw, ug_info->extrabw);
for (i = 0; i < NUM_TX_QUEUES; i++)
- ugeth->p_scheduler->weightfactor[i] =
- ug_info->weightfactor[i];
+ out_8(&ugeth->p_scheduler->weightfactor[i],
+ ug_info->weightfactor[i]);
/* Set pointers to cpucount registers in scheduler */
ugeth->p_cpucount[0] = &(ugeth->p_scheduler->cpucount0);
@@ -2890,10 +2898,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
ugeth->p_tx_fw_statistics_pram =
- (struct ucc_geth_tx_firmware_statistics_pram *)
+ (struct ucc_geth_tx_firmware_statistics_pram __iomem *)
qe_muram_addr(ugeth->tx_fw_statistics_pram_offset);
/* Zero out p_tx_fw_statistics_pram */
- memset(ugeth->p_tx_fw_statistics_pram,
+ memset_io((void __iomem *)ugeth->p_tx_fw_statistics_pram,
0, sizeof(struct ucc_geth_tx_firmware_statistics_pram));
}
@@ -2930,10 +2938,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
ugeth->p_rx_glbl_pram =
- (struct ucc_geth_rx_global_pram *) qe_muram_addr(ugeth->
+ (struct ucc_geth_rx_global_pram __iomem *) qe_muram_addr(ugeth->
rx_glbl_pram_offset);
/* Zero out p_rx_glbl_pram */
- memset(ugeth->p_rx_glbl_pram, 0, sizeof(struct ucc_geth_rx_global_pram));
+ memset_io((void __iomem *)ugeth->p_rx_glbl_pram, 0, sizeof(struct ucc_geth_rx_global_pram));
/* Fill global PRAM */
@@ -2953,7 +2961,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_thread_data_rx =
- (struct ucc_geth_thread_data_rx *) qe_muram_addr(ugeth->
+ (struct ucc_geth_thread_data_rx __iomem *) qe_muram_addr(ugeth->
thread_dat_rx_offset);
out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset);
@@ -2976,10 +2984,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
ugeth->p_rx_fw_statistics_pram =
- (struct ucc_geth_rx_firmware_statistics_pram *)
+ (struct ucc_geth_rx_firmware_statistics_pram __iomem *)
qe_muram_addr(ugeth->rx_fw_statistics_pram_offset);
/* Zero out p_rx_fw_statistics_pram */
- memset(ugeth->p_rx_fw_statistics_pram, 0,
+ memset_io((void __iomem *)ugeth->p_rx_fw_statistics_pram, 0,
sizeof(struct ucc_geth_rx_firmware_statistics_pram));
}
@@ -3000,7 +3008,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_rx_irq_coalescing_tbl =
- (struct ucc_geth_rx_interrupt_coalescing_table *)
+ (struct ucc_geth_rx_interrupt_coalescing_table __iomem *)
qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset);
out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr,
ugeth->rx_irq_coalescing_tbl_offset);
@@ -3069,11 +3077,11 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_rx_bd_qs_tbl =
- (struct ucc_geth_rx_bd_queues_entry *) qe_muram_addr(ugeth->
+ (struct ucc_geth_rx_bd_queues_entry __iomem *) qe_muram_addr(ugeth->
rx_bd_qs_tbl_offset);
out_be32(&ugeth->p_rx_glbl_pram->rbdqptr, ugeth->rx_bd_qs_tbl_offset);
/* Zero out p_rx_bd_qs_tbl */
- memset(ugeth->p_rx_bd_qs_tbl,
+ memset_io((void __iomem *)ugeth->p_rx_bd_qs_tbl,
0,
ug_info->numQueuesRx * (sizeof(struct ucc_geth_rx_bd_queues_entry) +
sizeof(struct ucc_geth_rx_prefetched_bds)));
@@ -3133,7 +3141,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
&ugeth->p_rx_glbl_pram->remoder);
/* function code register */
- ugeth->p_rx_glbl_pram->rstate = function_code;
+ out_8(&ugeth->p_rx_glbl_pram->rstate, function_code);
/* initialize extended filtering */
if (ug_info->rxExtendedFiltering) {
@@ -3160,7 +3168,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
}
ugeth->p_exf_glbl_param =
- (struct ucc_geth_exf_global_pram *) qe_muram_addr(ugeth->
+ (struct ucc_geth_exf_global_pram __iomem *) qe_muram_addr(ugeth->
exf_glbl_param_offset);
out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam,
ugeth->exf_glbl_param_offset);
@@ -3175,7 +3183,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j);
p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->
+ (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->
p_rx_glbl_pram->addressfiltering;
ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth,
@@ -3307,17 +3315,21 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
p_init_enet_pram =
- (struct ucc_geth_init_pram *) qe_muram_addr(init_enet_pram_offset);
+ (struct ucc_geth_init_pram __iomem *) qe_muram_addr(init_enet_pram_offset);
/* Copy shadow InitEnet command parameter structure into PRAM */
- p_init_enet_pram->resinit1 = ugeth->p_init_enet_param_shadow->resinit1;
- p_init_enet_pram->resinit2 = ugeth->p_init_enet_param_shadow->resinit2;
- p_init_enet_pram->resinit3 = ugeth->p_init_enet_param_shadow->resinit3;
- p_init_enet_pram->resinit4 = ugeth->p_init_enet_param_shadow->resinit4;
+ out_8(&p_init_enet_pram->resinit1,
+ ugeth->p_init_enet_param_shadow->resinit1);
+ out_8(&p_init_enet_pram->resinit2,
+ ugeth->p_init_enet_param_shadow->resinit2);
+ out_8(&p_init_enet_pram->resinit3,
+ ugeth->p_init_enet_param_shadow->resinit3);
+ out_8(&p_init_enet_pram->resinit4,
+ ugeth->p_init_enet_param_shadow->resinit4);
out_be16(&p_init_enet_pram->resinit5,
ugeth->p_init_enet_param_shadow->resinit5);
- p_init_enet_pram->largestexternallookupkeysize =
- ugeth->p_init_enet_param_shadow->largestexternallookupkeysize;
+ out_8(&p_init_enet_pram->largestexternallookupkeysize,
+ ugeth->p_init_enet_param_shadow->largestexternallookupkeysize);
out_be32(&p_init_enet_pram->rgftgfrxglobal,
ugeth->p_init_enet_param_shadow->rgftgfrxglobal);
for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++)
@@ -3371,7 +3383,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef CONFIG_UGETH_TX_ON_DEMAND
struct ucc_fast_private *uccf;
#endif
- u8 *bd; /* BD pointer */
+ u8 __iomem *bd; /* BD pointer */
u32 bd_status;
u8 txQ = 0;
@@ -3383,7 +3395,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Start from the next BD that should be filled */
bd = ugeth->txBd[txQ];
- bd_status = in_be32((u32 *)bd);
+ bd_status = in_be32((u32 __iomem *)bd);
/* Save the skb pointer so we can free it later */
ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb;
@@ -3393,7 +3405,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
/* set up the buffer descriptor */
- out_be32(&((struct qe_bd *)bd)->buf,
+ out_be32(&((struct qe_bd __iomem *)bd)->buf,
dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE));
/* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
@@ -3401,7 +3413,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
bd_status = (bd_status & T_W) | T_R | T_I | T_L | skb->len;
/* set bd status and length */
- out_be32((u32 *)bd, bd_status);
+ out_be32((u32 __iomem *)bd, bd_status);
dev->trans_start = jiffies;
@@ -3441,7 +3453,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
{
struct sk_buff *skb;
- u8 *bd;
+ u8 __iomem *bd;
u16 length, howmany = 0;
u32 bd_status;
u8 *bdBuffer;
@@ -3454,11 +3466,11 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
- bd_status = in_be32((u32 *)bd);
+ bd_status = in_be32((u32 __iomem *)bd);
/* while there are received buffers and BD is full (~R_E) */
while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) {
- bdBuffer = (u8 *) in_be32(&((struct qe_bd *)bd)->buf);
+ bdBuffer = (u8 *) in_be32(&((struct qe_bd __iomem *)bd)->buf);
length = (u16) ((bd_status & BD_LENGTH_MASK) - 4);
skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]];
@@ -3516,7 +3528,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
else
bd += sizeof(struct qe_bd);
- bd_status = in_be32((u32 *)bd);
+ bd_status = in_be32((u32 __iomem *)bd);
}
ugeth->rxBd[rxQ] = bd;
@@ -3527,11 +3539,11 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
{
/* Start from the next BD that should be filled */
struct ucc_geth_private *ugeth = netdev_priv(dev);
- u8 *bd; /* BD pointer */
+ u8 __iomem *bd; /* BD pointer */
u32 bd_status;
bd = ugeth->confBd[txQ];
- bd_status = in_be32((u32 *)bd);
+ bd_status = in_be32((u32 __iomem *)bd);
/* Normal processing. */
while ((bd_status & T_R) == 0) {
@@ -3561,7 +3573,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
bd += sizeof(struct qe_bd);
else
bd = ugeth->p_tx_bd_ring[txQ];
- bd_status = in_be32((u32 *)bd);
+ bd_status = in_be32((u32 __iomem *)bd);
}
ugeth->confBd[txQ] = bd;
return 0;
@@ -3910,7 +3922,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
return -EINVAL;
}
} else {
- prop = of_get_property(np, "rx-clock", NULL);
+ prop = of_get_property(np, "tx-clock", NULL);
if (!prop) {
printk(KERN_ERR
"ucc_geth: mising tx-clock-name property\n");
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 9f8b7580a3a4..abc0e2242634 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -700,8 +700,8 @@ struct ucc_geth_82xx_address_filtering_pram {
u32 iaddr_l; /* individual address filter, low */
u32 gaddr_h; /* group address filter, high */
u32 gaddr_l; /* group address filter, low */
- struct ucc_geth_82xx_enet_address taddr;
- struct ucc_geth_82xx_enet_address paddr[NUM_OF_PADDRS];
+ struct ucc_geth_82xx_enet_address __iomem taddr;
+ struct ucc_geth_82xx_enet_address __iomem paddr[NUM_OF_PADDRS];
u8 res0[0x40 - 0x38];
} __attribute__ ((packed));
@@ -1186,40 +1186,40 @@ struct ucc_geth_private {
struct ucc_fast_private *uccf;
struct net_device *dev;
struct napi_struct napi;
- struct ucc_geth *ug_regs;
+ struct ucc_geth __iomem *ug_regs;
struct ucc_geth_init_pram *p_init_enet_param_shadow;
- struct ucc_geth_exf_global_pram *p_exf_glbl_param;
+ struct ucc_geth_exf_global_pram __iomem *p_exf_glbl_param;
u32 exf_glbl_param_offset;
- struct ucc_geth_rx_global_pram *p_rx_glbl_pram;
+ struct ucc_geth_rx_global_pram __iomem *p_rx_glbl_pram;
u32 rx_glbl_pram_offset;
- struct ucc_geth_tx_global_pram *p_tx_glbl_pram;
+ struct ucc_geth_tx_global_pram __iomem *p_tx_glbl_pram;
u32 tx_glbl_pram_offset;
- struct ucc_geth_send_queue_mem_region *p_send_q_mem_reg;
+ struct ucc_geth_send_queue_mem_region __iomem *p_send_q_mem_reg;
u32 send_q_mem_reg_offset;
- struct ucc_geth_thread_data_tx *p_thread_data_tx;
+ struct ucc_geth_thread_data_tx __iomem *p_thread_data_tx;
u32 thread_dat_tx_offset;
- struct ucc_geth_thread_data_rx *p_thread_data_rx;
+ struct ucc_geth_thread_data_rx __iomem *p_thread_data_rx;
u32 thread_dat_rx_offset;
- struct ucc_geth_scheduler *p_scheduler;
+ struct ucc_geth_scheduler __iomem *p_scheduler;
u32 scheduler_offset;
- struct ucc_geth_tx_firmware_statistics_pram *p_tx_fw_statistics_pram;
+ struct ucc_geth_tx_firmware_statistics_pram __iomem *p_tx_fw_statistics_pram;
u32 tx_fw_statistics_pram_offset;
- struct ucc_geth_rx_firmware_statistics_pram *p_rx_fw_statistics_pram;
+ struct ucc_geth_rx_firmware_statistics_pram __iomem *p_rx_fw_statistics_pram;
u32 rx_fw_statistics_pram_offset;
- struct ucc_geth_rx_interrupt_coalescing_table *p_rx_irq_coalescing_tbl;
+ struct ucc_geth_rx_interrupt_coalescing_table __iomem *p_rx_irq_coalescing_tbl;
u32 rx_irq_coalescing_tbl_offset;
- struct ucc_geth_rx_bd_queues_entry *p_rx_bd_qs_tbl;
+ struct ucc_geth_rx_bd_queues_entry __iomem *p_rx_bd_qs_tbl;
u32 rx_bd_qs_tbl_offset;
- u8 *p_tx_bd_ring[NUM_TX_QUEUES];
+ u8 __iomem *p_tx_bd_ring[NUM_TX_QUEUES];
u32 tx_bd_ring_offset[NUM_TX_QUEUES];
- u8 *p_rx_bd_ring[NUM_RX_QUEUES];
+ u8 __iomem *p_rx_bd_ring[NUM_RX_QUEUES];
u32 rx_bd_ring_offset[NUM_RX_QUEUES];
- u8 *confBd[NUM_TX_QUEUES];
- u8 *txBd[NUM_TX_QUEUES];
- u8 *rxBd[NUM_RX_QUEUES];
+ u8 __iomem *confBd[NUM_TX_QUEUES];
+ u8 __iomem *txBd[NUM_TX_QUEUES];
+ u8 __iomem *rxBd[NUM_RX_QUEUES];
int badFrame[NUM_RX_QUEUES];
u16 cpucount[NUM_TX_QUEUES];
- volatile u16 *p_cpucount[NUM_TX_QUEUES];
+ u16 __iomem *p_cpucount[NUM_TX_QUEUES];
int indAddrRegUsed[NUM_OF_PADDRS];
u8 paddr[NUM_OF_PADDRS][ENET_NUM_OCTETS_PER_ADDRESS]; /* ethernet address */
u8 numGroupAddrInHash;
@@ -1251,4 +1251,12 @@ struct ucc_geth_private {
int oldlink;
};
+void uec_set_ethtool_ops(struct net_device *netdev);
+int init_flow_control_params(u32 automatic_flow_control_mode,
+ int rx_flow_control_enable, int tx_flow_control_enable,
+ u16 pause_period, u16 extension_field,
+ u32 __iomem *upsmr_register, u32 __iomem *uempr_register,
+ u32 __iomem *maccfg1_register);
+
+
#endif /* __UCC_GETH_H__ */
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 9a9622c13e2b..299b7f176950 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -108,12 +108,6 @@ static char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
#define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
#define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
-extern int init_flow_control_params(u32 automatic_flow_control_mode,
- int rx_flow_control_enable,
- int tx_flow_control_enable, u16 pause_period,
- u16 extension_field, volatile u32 *upsmr_register,
- volatile u32 *uempr_register, volatile u32 *maccfg1_register);
-
static int
uec_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index 2af490781005..940474736922 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -104,7 +104,7 @@ int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
}
/* Reset the MIIM registers, and wait for the bus to free */
-int uec_mdio_reset(struct mii_bus *bus)
+static int uec_mdio_reset(struct mii_bus *bus)
{
struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
@@ -240,7 +240,7 @@ reg_map_fail:
return err;
}
-int uec_mdio_remove(struct of_device *ofdev)
+static int uec_mdio_remove(struct of_device *ofdev)
{
struct device *device = &ofdev->dev;
struct mii_bus *bus = dev_get_drvdata(device);
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6f245cfb6624..dc6f097062df 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1381,6 +1381,10 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x0411, 0x003d),
.driver_info = (unsigned long) &ax8817x_info,
}, {
+ // Buffalo LUA-U2-GT 10/100/1000
+ USB_DEVICE (0x0411, 0x006e),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
// Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
USB_DEVICE (0x6189, 0x182d),
.driver_info = (unsigned long) &ax8817x_info,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 555b70c8b863..f926b5ab3d09 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -41,6 +41,9 @@ struct virtnet_info
struct net_device *dev;
struct napi_struct napi;
+ /* The skb we couldn't send because buffers were full. */
+ struct sk_buff *last_xmit_skb;
+
/* Number of input buffers, and max we've ever had. */
unsigned int num, max;
@@ -142,10 +145,10 @@ drop:
static void try_fill_recv(struct virtnet_info *vi)
{
struct sk_buff *skb;
- struct scatterlist sg[1+MAX_SKB_FRAGS];
+ struct scatterlist sg[2+MAX_SKB_FRAGS];
int num, err;
- sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ sg_init_table(sg, 2+MAX_SKB_FRAGS);
for (;;) {
skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
if (unlikely(!skb))
@@ -221,23 +224,22 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
pr_debug("Sent skb %p\n", skb);
__skb_unlink(skb, &vi->send);
- vi->dev->stats.tx_bytes += len;
+ vi->dev->stats.tx_bytes += skb->len;
vi->dev->stats.tx_packets++;
kfree_skb(skb);
}
}
-static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
{
- struct virtnet_info *vi = netdev_priv(dev);
- int num, err;
- struct scatterlist sg[1+MAX_SKB_FRAGS];
+ int num;
+ struct scatterlist sg[2+MAX_SKB_FRAGS];
struct virtio_net_hdr *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
- sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ sg_init_table(sg, 2+MAX_SKB_FRAGS);
- pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb,
+ pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb,
dest[0], dest[1], dest[2],
dest[3], dest[4], dest[5]);
@@ -272,30 +274,51 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- __skb_queue_head(&vi->send, skb);
+
+ return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+}
+
+static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
again:
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(vi);
- err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
- if (err) {
- pr_debug("%s: virtio not prepared to send\n", dev->name);
- netif_stop_queue(dev);
-
- /* Activate callback for using skbs: if this returns false it
- * means some were used in the meantime. */
- if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
- vi->svq->vq_ops->disable_cb(vi->svq);
- netif_start_queue(dev);
- goto again;
+
+ /* If we has a buffer left over from last time, send it now. */
+ if (vi->last_xmit_skb) {
+ if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
+ /* Drop this skb: we only queue one. */
+ vi->dev->stats.tx_dropped++;
+ kfree_skb(skb);
+ goto stop_queue;
}
- __skb_unlink(skb, &vi->send);
+ vi->last_xmit_skb = NULL;
+ }
- return NETDEV_TX_BUSY;
+ /* Put new one in send queue and do transmit */
+ __skb_queue_head(&vi->send, skb);
+ if (xmit_skb(vi, skb) != 0) {
+ vi->last_xmit_skb = skb;
+ goto stop_queue;
}
+done:
vi->svq->vq_ops->kick(vi->svq);
-
- return 0;
+ return NETDEV_TX_OK;
+
+stop_queue:
+ pr_debug("%s: virtio not prepared to send\n", dev->name);
+ netif_stop_queue(dev);
+
+ /* Activate callback for using skbs: if this returns false it
+ * means some were used in the meantime. */
+ if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+ vi->svq->vq_ops->disable_cb(vi->svq);
+ netif_start_queue(dev);
+ goto again;
+ }
+ goto done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -355,17 +378,26 @@ static int virtnet_probe(struct virtio_device *vdev)
SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */
- if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
+ if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
- if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
dev->features |= NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
+ /* Individual feature bits: what can host handle? */
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
+ dev->features |= NETIF_F_TSO;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
+ dev->features |= NETIF_F_TSO6;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
+ dev->features |= NETIF_F_TSO_ECN;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+ dev->features |= NETIF_F_UFO;
}
/* Configuration may specify what MAC to use. Otherwise random. */
- if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
vdev->config->get(vdev,
offsetof(struct virtio_net_config, mac),
dev->dev_addr, dev->addr_len);
@@ -454,7 +486,15 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};
+static unsigned int features[] = {
+ VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
+ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
+ VIRTIO_NET_F_HOST_ECN,
+};
+
static struct virtio_driver virtio_net = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 8005dd16fb4e..d5140aed7b79 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -150,11 +150,9 @@ config HDLC_FR
config HDLC_PPP
tristate "Synchronous Point-to-Point Protocol (PPP) support"
- depends on HDLC && BROKEN
+ depends on HDLC
help
Generic HDLC driver supporting PPP over WAN connections.
- This module is currently broken and will cause a kernel panic
- when a device configured in PPP mode is activated.
It will be replaced by new PPP implementation in Linux 2.6.26.
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 45ddfc9763cc..b0fce1387eaf 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -629,7 +629,7 @@ static void sppp_channel_init(struct channel_data *chan)
d->base_addr = chan->cosa->datareg;
d->irq = chan->cosa->irq;
d->dma = chan->cosa->dma;
- d->priv = chan;
+ d->ml_priv = chan;
sppp_attach(&chan->pppdev);
if (register_netdev(d)) {
printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
@@ -650,7 +650,7 @@ static void sppp_channel_delete(struct channel_data *chan)
static int cosa_sppp_open(struct net_device *d)
{
- struct channel_data *chan = d->priv;
+ struct channel_data *chan = d->ml_priv;
int err;
unsigned long flags;
@@ -690,7 +690,7 @@ static int cosa_sppp_open(struct net_device *d)
static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
{
- struct channel_data *chan = dev->priv;
+ struct channel_data *chan = dev->ml_priv;
netif_stop_queue(dev);
@@ -701,7 +701,7 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
static void cosa_sppp_timeout(struct net_device *dev)
{
- struct channel_data *chan = dev->priv;
+ struct channel_data *chan = dev->ml_priv;
if (test_bit(RXBIT, &chan->cosa->rxtx)) {
chan->stats.rx_errors++;
@@ -720,7 +720,7 @@ static void cosa_sppp_timeout(struct net_device *dev)
static int cosa_sppp_close(struct net_device *d)
{
- struct channel_data *chan = d->priv;
+ struct channel_data *chan = d->ml_priv;
unsigned long flags;
netif_stop_queue(d);
@@ -800,7 +800,7 @@ static int sppp_tx_done(struct channel_data *chan, int size)
static struct net_device_stats *cosa_net_stats(struct net_device *dev)
{
- struct channel_data *chan = dev->priv;
+ struct channel_data *chan = dev->ml_priv;
return &chan->stats;
}
@@ -1217,7 +1217,7 @@ static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr,
int cmd)
{
int rv;
- struct channel_data *chan = dev->priv;
+ struct channel_data *chan = dev->ml_priv;
rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data);
if (rv == -ENOIOCTLCMD) {
return sppp_do_ioctl(dev, ifr, cmd);
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 10396d9686f4..00308337928e 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -45,7 +45,7 @@ static int ppp_open(struct net_device *dev)
int (*old_ioctl)(struct net_device *, struct ifreq *, int);
int result;
- dev->priv = &state(hdlc)->syncppp_ptr;
+ dev->ml_priv = &state(hdlc)->syncppp_ptr;
state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
state(hdlc)->pppdev.dev = dev;
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 83dbc924fcb5..f3065d3473fd 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -75,7 +75,7 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb)
static int hostess_open(struct net_device *d)
{
- struct sv11_device *sv11=d->priv;
+ struct sv11_device *sv11=d->ml_priv;
int err = -1;
/*
@@ -128,7 +128,7 @@ static int hostess_open(struct net_device *d)
static int hostess_close(struct net_device *d)
{
- struct sv11_device *sv11=d->priv;
+ struct sv11_device *sv11=d->ml_priv;
/*
* Discard new frames
*/
@@ -159,14 +159,14 @@ static int hostess_close(struct net_device *d)
static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
{
- /* struct sv11_device *sv11=d->priv;
+ /* struct sv11_device *sv11=d->ml_priv;
z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
return sppp_do_ioctl(d, ifr,cmd);
}
static struct net_device_stats *hostess_get_stats(struct net_device *d)
{
- struct sv11_device *sv11=d->priv;
+ struct sv11_device *sv11=d->ml_priv;
if(sv11)
return z8530_get_stats(&sv11->sync.chanA);
else
@@ -179,7 +179,7 @@ static struct net_device_stats *hostess_get_stats(struct net_device *d)
static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d)
{
- struct sv11_device *sv11=d->priv;
+ struct sv11_device *sv11=d->ml_priv;
return z8530_queue_xmit(&sv11->sync.chanA, skb);
}
@@ -325,6 +325,7 @@ static struct sv11_device *sv11_init(int iobase, int irq)
/*
* Initialise the PPP components
*/
+ d->ml_priv = sv;
sppp_attach(&sv->netdev);
/*
@@ -333,7 +334,6 @@ static struct sv11_device *sv11_init(int iobase, int irq)
d->base_addr = iobase;
d->irq = irq;
- d->priv = sv;
if(register_netdev(d))
{
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index b5860b97a93e..24fd613466b7 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -459,6 +459,7 @@ static void __exit lapbeth_cleanup_driver(void)
list_for_each_safe(entry, tmp, &lapbeth_devices) {
lapbeth = list_entry(entry, struct lapbethdev, node);
+ dev_put(lapbeth->ethdev);
unregister_netdevice(lapbeth->axdev);
}
rtnl_unlock();
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 6635ecef36e5..62133cee446a 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -891,6 +891,7 @@ static int __devinit lmc_init_one(struct pci_dev *pdev,
/* Initialize the sppp layer */
/* An ioctl can cause a subsequent detach for raw frame interface */
+ dev->ml_priv = sc;
sc->if_type = LMC_PPP;
sc->check = 0xBEAFCAFE;
dev->base_addr = pci_resource_start(pdev, 0);
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 63abfd72542d..e03eef2f2282 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -178,6 +178,20 @@ static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal)
CPC_TTY_UNLOCK(card,flags);
}
+
+static const struct tty_operations pc300_ops = {
+ .open = cpc_tty_open,
+ .close = cpc_tty_close,
+ .write = cpc_tty_write,
+ .write_room = cpc_tty_write_room,
+ .chars_in_buffer = cpc_tty_chars_in_buffer,
+ .tiocmset = pc300_tiocmset,
+ .tiocmget = pc300_tiocmget,
+ .flush_buffer = cpc_tty_flush_buffer,
+ .hangup = cpc_tty_hangup,
+};
+
+
/*
* PC300 TTY initialization routine
*
@@ -225,15 +239,7 @@ void cpc_tty_init(pc300dev_t *pc300dev)
serial_drv.flags = TTY_DRIVER_REAL_RAW;
/* interface routines from the upper tty layer to the tty driver */
- serial_drv.open = cpc_tty_open;
- serial_drv.close = cpc_tty_close;
- serial_drv.write = cpc_tty_write;
- serial_drv.write_room = cpc_tty_write_room;
- serial_drv.chars_in_buffer = cpc_tty_chars_in_buffer;
- serial_drv.tiocmset = pc300_tiocmset;
- serial_drv.tiocmget = pc300_tiocmget;
- serial_drv.flush_buffer = cpc_tty_flush_buffer;
- serial_drv.hangup = cpc_tty_hangup;
+ tty_set_operations(&serial_drv, &pc300_ops);
/* register the TTY driver */
if (tty_register_driver(&serial_drv)) {
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 11276bf3149f..44a89df1b8bf 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -241,6 +241,7 @@ static inline struct slvl_device *slvl_alloc(int iobase, int irq)
return NULL;
sv = d->priv;
+ d->ml_priv = sv;
sv->if_ptr = &sv->pppdev;
sv->pppdev.dev = d;
d->base_addr = iobase;
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 0f8aca8a4d43..249e18053d5f 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -17,7 +17,7 @@
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -95,7 +95,7 @@ static struct x25_asy *x25_asy_alloc(void)
x25_asy_devs[i] = dev;
return sl;
} else {
- printk("x25_asy_alloc() - register_netdev() failure.\n");
+ printk(KERN_WARNING "x25_asy_alloc() - register_netdev() failure.\n");
free_netdev(dev);
}
}
@@ -112,23 +112,22 @@ static void x25_asy_free(struct x25_asy *sl)
kfree(sl->xbuff);
sl->xbuff = NULL;
- if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
- printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
- }
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags))
+ printk(KERN_ERR "%s: x25_asy_free for already free unit.\n",
+ sl->dev->name);
}
static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
{
struct x25_asy *sl = dev->priv;
unsigned char *xbuff, *rbuff;
- int len = 2* newmtu;
+ int len = 2 * newmtu;
xbuff = kmalloc(len + 4, GFP_ATOMIC);
rbuff = kmalloc(len + 4, GFP_ATOMIC);
- if (xbuff == NULL || rbuff == NULL)
- {
- printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
+ if (xbuff == NULL || rbuff == NULL) {
+ printk(KERN_WARNING "%s: unable to grow X.25 buffers, MTU change cancelled.\n",
dev->name);
kfree(xbuff);
kfree(rbuff);
@@ -193,25 +192,23 @@ static void x25_asy_bump(struct x25_asy *sl)
int err;
count = sl->rcount;
- sl->stats.rx_bytes+=count;
-
+ sl->stats.rx_bytes += count;
+
skb = dev_alloc_skb(count+1);
- if (skb == NULL)
- {
- printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n",
+ sl->dev->name);
sl->stats.rx_dropped++;
return;
}
- skb_push(skb,1); /* LAPB internal control */
- memcpy(skb_put(skb,count), sl->rbuff, count);
+ skb_push(skb, 1); /* LAPB internal control */
+ memcpy(skb_put(skb, count), sl->rbuff, count);
skb->protocol = x25_type_trans(skb, sl->dev);
- if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK)
- {
+ err = lapb_data_received(skb->dev, skb);
+ if (err != LAPB_OK) {
kfree_skb(skb);
- printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
- }
- else
- {
+ printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
+ } else {
netif_rx(skb);
sl->dev->last_rx = jiffies;
sl->stats.rx_packets++;
@@ -224,10 +221,11 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
unsigned char *p;
int actual, count, mtu = sl->dev->mtu;
- if (len > mtu)
- { /* Sigh, shouldn't occur BUT ... */
+ if (len > mtu) {
+ /* Sigh, shouldn't occur BUT ... */
len = mtu;
- printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
+ printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n",
+ sl->dev->name);
sl->stats.tx_dropped++;
x25_asy_unlock(sl);
return;
@@ -245,7 +243,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
* 14 Oct 1994 Dmitry Gorodchanin.
*/
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
sl->xleft = count - actual;
sl->xhead = sl->xbuff + actual;
/* VSV */
@@ -265,8 +263,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
- if (sl->xleft <= 0)
- {
+ if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sl->stats.tx_packets++;
@@ -275,14 +272,14 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
return;
}
- actual = tty->driver->write(tty, sl->xhead, sl->xleft);
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
}
static void x25_asy_timeout(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
spin_lock(&sl->lock);
if (netif_queue_stopped(dev)) {
@@ -290,7 +287,7 @@ static void x25_asy_timeout(struct net_device *dev)
* 14 Oct 1994 Dmitry Gorodchanin.
*/
printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+ (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error");
sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@@ -303,31 +300,34 @@ static void x25_asy_timeout(struct net_device *dev)
static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
int err;
if (!netif_running(sl->dev)) {
- printk("%s: xmit call when iface is down\n", dev->name);
+ printk(KERN_ERR "%s: xmit call when iface is down\n",
+ dev->name);
kfree_skb(skb);
return 0;
}
-
- switch(skb->data[0])
- {
- case 0x00:break;
- case 0x01: /* Connection request .. do nothing */
- if((err=lapb_connect_request(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
- kfree_skb(skb);
- return 0;
- case 0x02: /* Disconnect request .. do nothing - hang up ?? */
- if((err=lapb_disconnect_request(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
- default:
- kfree_skb(skb);
- return 0;
+
+ switch (skb->data[0]) {
+ case 0x00:
+ break;
+ case 0x01: /* Connection request .. do nothing */
+ err = lapb_connect_request(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
+ kfree_skb(skb);
+ return 0;
+ case 0x02: /* Disconnect request .. do nothing - hang up ?? */
+ err = lapb_disconnect_request(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
+ default:
+ kfree_skb(skb);
+ return 0;
}
- skb_pull(skb,1); /* Remove control byte */
+ skb_pull(skb, 1); /* Remove control byte */
/*
* If we are busy already- too bad. We ought to be able
* to queue things at this point, to allow for a little
@@ -338,10 +338,10 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* So, no queues !
* 14 Oct 1994 Dmitry Gorodchanin.
*/
-
- if((err=lapb_data_request(dev,skb))!=LAPB_OK)
- {
- printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
+
+ err = lapb_data_request(dev, skb);
+ if (err != LAPB_OK) {
+ printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb);
return 0;
}
@@ -357,7 +357,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* Called when I frame data arrives. We did the work above - throw it
* at the net layer.
*/
-
+
static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
{
skb->dev->last_rx = jiffies;
@@ -369,24 +369,22 @@ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
* busy cases too well. Its tricky to see how to do this nicely -
* perhaps lapb should allow us to bounce this ?
*/
-
+
static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
{
- struct x25_asy *sl=dev->priv;
-
+ struct x25_asy *sl = dev->priv;
+
spin_lock(&sl->lock);
- if (netif_queue_stopped(sl->dev) || sl->tty == NULL)
- {
+ if (netif_queue_stopped(sl->dev) || sl->tty == NULL) {
spin_unlock(&sl->lock);
printk(KERN_ERR "x25_asy: tbusy drop\n");
kfree_skb(skb);
return;
}
/* We were not busy, so we are now... :-) */
- if (skb != NULL)
- {
+ if (skb != NULL) {
x25_asy_lock(sl);
- sl->stats.tx_bytes+=skb->len;
+ sl->stats.tx_bytes += skb->len;
x25_asy_encaps(sl, skb->data, skb->len);
dev_kfree_skb(skb);
}
@@ -396,15 +394,16 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
/*
* LAPB connection establish/down information.
*/
-
+
static void x25_asy_connected(struct net_device *dev, int reason)
{
struct x25_asy *sl = dev->priv;
struct sk_buff *skb;
unsigned char *ptr;
- if ((skb = dev_alloc_skb(1)) == NULL) {
- printk(KERN_ERR "lapbeth: out of memory\n");
+ skb = dev_alloc_skb(1);
+ if (skb == NULL) {
+ printk(KERN_ERR "x25_asy: out of memory\n");
return;
}
@@ -422,7 +421,8 @@ static void x25_asy_disconnected(struct net_device *dev, int reason)
struct sk_buff *skb;
unsigned char *ptr;
- if ((skb = dev_alloc_skb(1)) == NULL) {
+ skb = dev_alloc_skb(1);
+ if (skb == NULL) {
printk(KERN_ERR "x25_asy: out of memory\n");
return;
}
@@ -449,7 +449,7 @@ static struct lapb_register_struct x25_asy_callbacks = {
/* Open the low-level part of the X.25 channel. Easy! */
static int x25_asy_open(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
unsigned long len;
int err;
@@ -466,13 +466,11 @@ static int x25_asy_open(struct net_device *dev)
len = dev->mtu * 2;
sl->rbuff = kmalloc(len + 4, GFP_KERNEL);
- if (sl->rbuff == NULL) {
+ if (sl->rbuff == NULL)
goto norbuff;
- }
sl->xbuff = kmalloc(len + 4, GFP_KERNEL);
- if (sl->xbuff == NULL) {
+ if (sl->xbuff == NULL)
goto noxbuff;
- }
sl->buffsize = len;
sl->rcount = 0;
@@ -480,11 +478,12 @@ static int x25_asy_open(struct net_device *dev)
sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
netif_start_queue(dev);
-
+
/*
* Now attach LAPB
*/
- if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK)
+ err = lapb_register(dev, &x25_asy_callbacks);
+ if (err == LAPB_OK)
return 0;
/* Cleanup */
@@ -499,18 +498,20 @@ norbuff:
/* Close the low-level part of the X.25 channel. Easy! */
static int x25_asy_close(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
int err;
spin_lock(&sl->lock);
- if (sl->tty)
+ if (sl->tty)
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
netif_stop_queue(dev);
sl->rcount = 0;
sl->xleft = 0;
- if((err=lapb_unregister(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
+ err = lapb_unregister(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
+ err);
spin_unlock(&sl->lock);
return 0;
}
@@ -521,8 +522,9 @@ static int x25_asy_close(struct net_device *dev)
* a block of X.25 data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
-
-static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+
+static void x25_asy_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
@@ -533,9 +535,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->stats.rx_errors++;
- }
cp++;
continue;
}
@@ -556,31 +557,31 @@ static int x25_asy_open_tty(struct tty_struct *tty)
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
/* First make sure we're not already connected. */
- if (sl && sl->magic == X25_ASY_MAGIC) {
+ if (sl && sl->magic == X25_ASY_MAGIC)
return -EEXIST;
- }
/* OK. Find a free X.25 channel to use. */
- if ((sl = x25_asy_alloc()) == NULL) {
+ sl = x25_asy_alloc();
+ if (sl == NULL)
return -ENFILE;
- }
sl->tty = tty;
tty->disc_data = sl;
tty->receive_room = 65536;
- if (tty->driver->flush_buffer) {
- tty->driver->flush_buffer(tty);
- }
+ tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
/* Restore default settings */
sl->dev->type = ARPHRD_X25;
-
+
/* Perform the low-level X.25 async init */
- if ((err = x25_asy_open(sl->dev)))
+ err = x25_asy_open(sl->dev);
+ if (err)
return err;
-
/* Done. We have linked the TTY line to a channel. */
return sl->dev->base_addr;
}
@@ -601,9 +602,7 @@ static void x25_asy_close_tty(struct tty_struct *tty)
return;
if (sl->dev->flags & IFF_UP)
- {
- (void) dev_close(sl->dev);
- }
+ dev_close(sl->dev);
tty->disc_data = NULL;
sl->tty = NULL;
@@ -613,8 +612,7 @@ static void x25_asy_close_tty(struct tty_struct *tty)
static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-
+ struct x25_asy *sl = dev->priv;
return &sl->stats;
}
@@ -641,21 +639,19 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
* character sequence, according to the X.25 protocol.
*/
- while (len-- > 0)
- {
- switch(c = *s++)
- {
- case X25_END:
- *ptr++ = X25_ESC;
- *ptr++ = X25_ESCAPE(X25_END);
- break;
- case X25_ESC:
- *ptr++ = X25_ESC;
- *ptr++ = X25_ESCAPE(X25_ESC);
- break;
- default:
- *ptr++ = c;
- break;
+ while (len-- > 0) {
+ switch (c = *s++) {
+ case X25_END:
+ *ptr++ = X25_ESC;
+ *ptr++ = X25_ESCAPE(X25_END);
+ break;
+ case X25_ESC:
+ *ptr++ = X25_ESC;
+ *ptr++ = X25_ESCAPE(X25_ESC);
+ break;
+ default:
+ *ptr++ = c;
+ break;
}
}
*ptr++ = X25_END;
@@ -665,31 +661,25 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
{
- switch(s)
- {
- case X25_END:
- if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
- {
- x25_asy_bump(sl);
- }
- clear_bit(SLF_ESCAPE, &sl->flags);
- sl->rcount = 0;
- return;
-
- case X25_ESC:
- set_bit(SLF_ESCAPE, &sl->flags);
- return;
-
- case X25_ESCAPE(X25_ESC):
- case X25_ESCAPE(X25_END):
- if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
- s = X25_UNESCAPE(s);
- break;
- }
- if (!test_bit(SLF_ERROR, &sl->flags))
- {
- if (sl->rcount < sl->buffsize)
- {
+ switch (s) {
+ case X25_END:
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
+ && sl->rcount > 2)
+ x25_asy_bump(sl);
+ clear_bit(SLF_ESCAPE, &sl->flags);
+ sl->rcount = 0;
+ return;
+ case X25_ESC:
+ set_bit(SLF_ESCAPE, &sl->flags);
+ return;
+ case X25_ESCAPE(X25_ESC):
+ case X25_ESCAPE(X25_END):
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
+ s = X25_UNESCAPE(s);
+ break;
+ }
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < sl->buffsize) {
sl->rbuff[sl->rcount++] = s;
return;
}
@@ -709,7 +699,7 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
if (!sl || sl->magic != X25_ASY_MAGIC)
return -EINVAL;
- switch(cmd) {
+ switch (cmd) {
case SIOCGIFNAME:
if (copy_to_user((void __user *)arg, sl->dev->name,
strlen(sl->dev->name) + 1))
@@ -724,8 +714,8 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
static int x25_asy_open_dev(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
- if(sl->tty==NULL)
+ struct x25_asy *sl = dev->priv;
+ if (sl->tty == NULL)
return -ENODEV;
return 0;
}
@@ -741,9 +731,9 @@ static void x25_asy_setup(struct net_device *dev)
set_bit(SLF_INUSE, &sl->flags);
/*
- * Finish setting up the DEVICE info.
+ * Finish setting up the DEVICE info.
*/
-
+
dev->mtu = SL_MTU;
dev->hard_start_xmit = x25_asy_xmit;
dev->tx_timeout = x25_asy_timeout;
@@ -778,9 +768,10 @@ static int __init init_x25_asy(void)
x25_asy_maxdev = 4; /* Sanity */
printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
- "(dynamic channels, max=%d).\n", x25_asy_maxdev );
+ "(dynamic channels, max=%d).\n", x25_asy_maxdev);
- x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL);
+ x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device *),
+ GFP_KERNEL);
if (!x25_asy_devs) {
printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
"array! Uaargh! (-> No X.25 available)\n");
@@ -802,7 +793,7 @@ static void __exit exit_x25_asy(void)
struct x25_asy *sl = dev->priv;
spin_lock_bh(&sl->lock);
- if (sl->tty)
+ if (sl->tty)
tty_hangup(sl->tty);
spin_unlock_bh(&sl->lock);
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 932d6b1c9d0b..45f47c1c0a35 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -3657,7 +3657,7 @@ void mpi_receive_802_11 (struct airo_info *ai)
ptr += hdrlen;
if (hdrlen == 24)
ptr += 6;
- gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
+ gap = get_unaligned_le16(ptr);
ptr += sizeof(__le16);
if (gap) {
if (gap <= 8)
@@ -4347,24 +4347,28 @@ static int proc_config_open( struct inode *inode, struct file *file );
static int proc_wepkey_open( struct inode *inode, struct file *file );
static const struct file_operations proc_statsdelta_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.open = proc_statsdelta_open,
.release = proc_close
};
static const struct file_operations proc_stats_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.open = proc_stats_open,
.release = proc_close
};
static const struct file_operations proc_status_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.open = proc_status_open,
.release = proc_close
};
static const struct file_operations proc_SSID_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_SSID_open,
@@ -4372,6 +4376,7 @@ static const struct file_operations proc_SSID_ops = {
};
static const struct file_operations proc_BSSList_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_BSSList_open,
@@ -4379,6 +4384,7 @@ static const struct file_operations proc_BSSList_ops = {
};
static const struct file_operations proc_APList_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_APList_open,
@@ -4386,6 +4392,7 @@ static const struct file_operations proc_APList_ops = {
};
static const struct file_operations proc_config_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_config_open,
@@ -4393,6 +4400,7 @@ static const struct file_operations proc_config_ops = {
};
static const struct file_operations proc_wepkey_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_wepkey_open,
@@ -4411,10 +4419,6 @@ struct proc_data {
void (*on_close) (struct inode *, struct file *);
};
-#ifndef SETPROC_OPS
-#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
-#endif
-
static int setup_proc_entry( struct net_device *dev,
struct airo_info *apriv ) {
struct proc_dir_entry *entry;
@@ -4430,100 +4434,76 @@ static int setup_proc_entry( struct net_device *dev,
apriv->proc_entry->owner = THIS_MODULE;
/* Setup the StatsDelta */
- entry = create_proc_entry("StatsDelta",
- S_IFREG | (S_IRUGO&proc_perm),
- apriv->proc_entry);
+ entry = proc_create_data("StatsDelta",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry)
goto fail_stats_delta;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_statsdelta_ops);
/* Setup the Stats */
- entry = create_proc_entry("Stats",
- S_IFREG | (S_IRUGO&proc_perm),
- apriv->proc_entry);
+ entry = proc_create_data("Stats",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry, &proc_stats_ops, dev);
if (!entry)
goto fail_stats;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_stats_ops);
/* Setup the Status */
- entry = create_proc_entry("Status",
- S_IFREG | (S_IRUGO&proc_perm),
- apriv->proc_entry);
+ entry = proc_create_data("Status",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry, &proc_status_ops, dev);
if (!entry)
goto fail_status;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_status_ops);
/* Setup the Config */
- entry = create_proc_entry("Config",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("Config",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_config_ops, dev);
if (!entry)
goto fail_config;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_config_ops);
/* Setup the SSID */
- entry = create_proc_entry("SSID",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("SSID",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_SSID_ops, dev);
if (!entry)
goto fail_ssid;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_SSID_ops);
/* Setup the APList */
- entry = create_proc_entry("APList",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("APList",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_APList_ops, dev);
if (!entry)
goto fail_aplist;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_APList_ops);
/* Setup the BSSList */
- entry = create_proc_entry("BSSList",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("BSSList",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_BSSList_ops, dev);
if (!entry)
goto fail_bsslist;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_BSSList_ops);
/* Setup the WepKey */
- entry = create_proc_entry("WepKey",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("WepKey",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_wepkey_ops, dev);
if (!entry)
goto fail_wepkey;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_wepkey_ops);
return 0;
@@ -5625,9 +5605,9 @@ static int __init airo_init_module( void )
int have_isa_dev = 0;
#endif
- airo_entry = create_proc_entry("aironet",
+ airo_entry = create_proc_entry("driver/aironet",
S_IFDIR | airo_perm,
- proc_root_driver);
+ NULL);
if (airo_entry) {
airo_entry->uid = proc_uid;
@@ -5651,7 +5631,7 @@ static int __init airo_init_module( void )
airo_print_info("", "Finished probing for PCI adapters");
if (i) {
- remove_proc_entry("aironet", proc_root_driver);
+ remove_proc_entry("driver/aironet", NULL);
return i;
}
#endif
@@ -5673,7 +5653,7 @@ static void __exit airo_cleanup_module( void )
#ifdef CONFIG_PCI
pci_unregister_driver(&airo_driver);
#endif
- remove_proc_entry("aironet", proc_root_driver);
+ remove_proc_entry("driver/aironet", NULL);
}
/*
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index e18305b781c9..4e5c8fc35200 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -58,10 +58,6 @@
#include "reg.h"
#include "debug.h"
-/* unaligned little endian access */
-#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p))))
-#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p))))
-
enum {
ATH_LED_TX,
ATH_LED_RX,
@@ -2909,9 +2905,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
if (!mclist)
break;
/* calculate XOR of eight 6-bit values */
- val = LE_READ_4(mclist->dmi_addr + 0);
+ val = get_unaligned_le32(mclist->dmi_addr + 0);
pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
- val = LE_READ_4(mclist->dmi_addr + 3);
+ val = get_unaligned_le32(mclist->dmi_addr + 3);
pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
pos &= 0x3f;
mfilt[pos / 32] |= (1 << (pos % 32));
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index ef2da4023d68..438e63ecccf1 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -47,6 +47,7 @@
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/timer.h>
+#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -60,7 +61,6 @@
#include <linux/delay.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
-#include <linux/byteorder/generic.h>
#include <linux/crc32.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index eff2a158a411..37783cdd301a 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -691,6 +691,10 @@ struct b43_wl {
struct mutex mutex;
spinlock_t irq_lock;
+ /* R/W lock for data transmission.
+ * Transmissions on 2+ queues can run concurrently, but somebody else
+ * might sync with TX by write_lock_irqsave()'ing. */
+ rwlock_t tx_lock;
/* Lock for LEDs access. */
spinlock_t leds_lock;
/* Lock for SHM access. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 4bf8a99099fe..8fdba9415c04 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -729,6 +729,7 @@ static void b43_synchronize_irq(struct b43_wldev *dev)
*/
void b43_dummy_transmission(struct b43_wldev *dev)
{
+ struct b43_wl *wl = dev->wl;
struct b43_phy *phy = &dev->phy;
unsigned int i, max_loop;
u16 value;
@@ -755,6 +756,9 @@ void b43_dummy_transmission(struct b43_wldev *dev)
return;
}
+ spin_lock_irq(&wl->irq_lock);
+ write_lock(&wl->tx_lock);
+
for (i = 0; i < 5; i++)
b43_ram_write(dev, i * 4, buffer[i]);
@@ -795,6 +799,9 @@ void b43_dummy_transmission(struct b43_wldev *dev)
}
if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
b43_radio_write16(dev, 0x0051, 0x0037);
+
+ write_unlock(&wl->tx_lock);
+ spin_unlock_irq(&wl->irq_lock);
}
static void key_write(struct b43_wldev *dev,
@@ -2171,7 +2178,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
goto err_format;
array_size -= sizeof(iv->data.d32);
- value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ value = get_unaligned_be32(&iv->data.d32);
b43_write32(dev, offset, value);
iv = (const struct b43_iv *)((const uint8_t *)iv +
@@ -2840,24 +2847,31 @@ static int b43_op_tx(struct ieee80211_hw *hw,
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev;
- int err = -ENODEV;
+ unsigned long flags;
+ int err;
if (unlikely(skb->len < 2 + 2 + 6)) {
/* Too short, this can't be a valid frame. */
- return -EINVAL;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
}
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
-
if (unlikely(!dev))
- goto out;
- if (unlikely(b43_status(dev) < B43_STAT_STARTED))
- goto out;
- /* TX is done without a global lock. */
- if (b43_using_pio_transfers(dev))
- err = b43_pio_tx(dev, skb, ctl);
- else
- err = b43_dma_tx(dev, skb, ctl);
-out:
+ return NETDEV_TX_BUSY;
+
+ /* Transmissions on seperate queues can run concurrently. */
+ read_lock_irqsave(&wl->tx_lock, flags);
+
+ err = -ENODEV;
+ if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
+ if (b43_using_pio_transfers(dev))
+ err = b43_pio_tx(dev, skb, ctl);
+ else
+ err = b43_dma_tx(dev, skb, ctl);
+ }
+
+ read_unlock_irqrestore(&wl->tx_lock, flags);
+
if (unlikely(err))
return NETDEV_TX_BUSY;
return NETDEV_TX_OK;
@@ -3476,7 +3490,9 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_synchronize_irq(dev);
+ write_lock_irqsave(&wl->tx_lock, flags);
b43_set_status(dev, B43_STAT_INITIALIZED);
+ write_unlock_irqrestore(&wl->tx_lock, flags);
b43_pio_stop(dev);
mutex_unlock(&wl->mutex);
@@ -3485,8 +3501,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
cancel_delayed_work_sync(&dev->periodic_work);
mutex_lock(&wl->mutex);
- ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy.
-
b43_mac_suspend(dev);
free_irq(dev->dev->irq, dev);
b43dbg(wl, "Wireless interface stopped\n");
@@ -4326,6 +4340,14 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
err = -EOPNOTSUPP;
goto err_powerdown;
}
+ if (1 /* disable A-PHY */) {
+ /* FIXME: For now we disable the A-PHY on multi-PHY devices. */
+ if (dev->phy.type != B43_PHYTYPE_N) {
+ have_2ghz_phy = 1;
+ have_5ghz_phy = 0;
+ }
+ }
+
dev->phy.gmode = have_2ghz_phy;
tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
b43_wireless_core_reset(dev, tmp);
@@ -4490,6 +4512,7 @@ static int b43_wireless_init(struct ssb_device *dev)
memset(wl, 0, sizeof(*wl));
wl->hw = hw;
spin_lock_init(&wl->irq_lock);
+ rwlock_init(&wl->tx_lock);
spin_lock_init(&wl->leds_lock);
spin_lock_init(&wl->shm_lock);
mutex_init(&wl->mutex);
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index ef829ee8ffd4..14a5eea2573e 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1720,7 +1720,7 @@ static int b43legacy_write_initvals(struct b43legacy_wldev *dev,
goto err_format;
array_size -= sizeof(iv->data.d32);
- value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ value = get_unaligned_be32(&iv->data.d32);
b43legacy_write32(dev, offset, value);
iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 9a25f550fd16..62fb89d82318 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,11 +1,14 @@
config IWLWIFI
- bool
- default n
+ tristate
config IWLCORE
tristate "Intel Wireless Wifi Core"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select IWLWIFI
+ select MAC80211_LEDS if IWLWIFI_LEDS
+ select LEDS_CLASS if IWLWIFI_LEDS
+ select RFKILL if IWLWIFI_RFKILL
+ select RFKILL_INPUT if IWLWIFI_RFKILL
config IWLWIFI_LEDS
bool
@@ -14,8 +17,6 @@ config IWLWIFI_LEDS
config IWLWIFI_RFKILL
boolean "IWLWIFI RF kill support"
depends on IWLCORE
- select RFKILL
- select RFKILL_INPUT
config IWL4965
tristate "Intel Wireless WiFi 4965AGN"
@@ -55,8 +56,6 @@ config IWL4965_HT
config IWL4965_LEDS
bool "Enable LEDS features in iwl4965 driver"
depends on IWL4965
- select MAC80211_LEDS
- select LEDS_CLASS
select IWLWIFI_LEDS
---help---
This option enables LEDS for the iwlwifi drivers
@@ -112,6 +111,8 @@ config IWL3945
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
select IWLWIFI
+ select MAC80211_LEDS if IWL3945_LEDS
+ select LEDS_CLASS if IWL3945_LEDS
---help---
Select to build the driver supporting the:
@@ -143,8 +144,6 @@ config IWL3945_SPECTRUM_MEASUREMENT
config IWL3945_LEDS
bool "Enable LEDS features in iwl3945 driver"
depends on IWL3945
- select MAC80211_LEDS
- select LEDS_CLASS
---help---
This option enables LEDS for the iwl3945 driver.
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 598e4eef4f40..62a3d8f8563e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -554,40 +554,36 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
iwl3945_rt->rt_hdr.it_pad = 0;
/* total header + data */
- put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)),
- &iwl3945_rt->rt_hdr.it_len);
+ put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len);
/* Indicate all the fields we add to the radiotap header */
- put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA)),
- &iwl3945_rt->rt_hdr.it_present);
+ put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA),
+ &iwl3945_rt->rt_hdr.it_present);
/* Zero the flags, we'll add to them as we go */
iwl3945_rt->rt_flags = 0;
- put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf);
+ put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf);
iwl3945_rt->rt_dbmsignal = signal;
iwl3945_rt->rt_dbmnoise = noise;
/* Convert the channel frequency and set the flags */
- put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz);
+ put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz);
if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ),
+ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
&iwl3945_rt->rt_chbitmask);
else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ),
+ put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
&iwl3945_rt->rt_chbitmask);
else /* 802.11g */
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_2GHZ),
+ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
&iwl3945_rt->rt_chbitmask);
if (rate == -1)
@@ -670,7 +666,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
rx_status.flag = 0;
rx_status.mactime = le64_to_cpu(rx_end->timestamp);
rx_status.freq =
- ieee80211_frequency_to_channel(le16_to_cpu(rx_hdr->channel));
+ ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel));
rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 45c1c5533bf0..c7695a215a39 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -742,7 +742,6 @@ struct iwl3945_priv {
u8 direct_ssid_len;
u8 direct_ssid[IW_ESSID_MAX_SIZE];
struct iwl3945_scan_cmd *scan;
- u8 only_active_channel;
/* spinlock */
spinlock_t lock; /* protect general shared data */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index b608e1ca8b40..c9847b1a67f7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -163,8 +163,8 @@ struct iwl4965_lq_sta {
struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
#endif
struct iwl4965_rate dbg_fixed;
- struct iwl_priv *drv;
#endif
+ struct iwl_priv *drv;
};
static void rs_rate_scale_perform(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 17f629fb96ff..bf19eb8aafd0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3978,7 +3978,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
rx_status.mactime = le64_to_cpu(rx_start->timestamp);
rx_status.freq =
- ieee80211_frequency_to_channel(le16_to_cpu(rx_start->channel));
+ ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel));
rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
rx_status.rate_idx =
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 9ed13cb0a2a9..581b98556c86 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -996,7 +996,6 @@ struct iwl_priv {
u8 direct_ssid_len;
u8 direct_ssid[IW_ESSID_MAX_SIZE];
struct iwl4965_scan_cmd *scan;
- u8 only_active_channel;
/* spinlock */
spinlock_t lock; /* protect general shared data */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index a1a0b3c581f1..13925b627e3b 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4968,17 +4968,6 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
if (channels[i].flags & IEEE80211_CHAN_DISABLED)
continue;
- if (channels[i].hw_value ==
- le16_to_cpu(priv->active_rxon.channel)) {
- if (iwl3945_is_associated(priv)) {
- IWL_DEBUG_SCAN
- ("Skipping current channel %d\n",
- le16_to_cpu(priv->active_rxon.channel));
- continue;
- }
- } else if (priv->only_active_channel)
- continue;
-
scan_ch->channel = channels[i].hw_value;
ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel);
@@ -6303,12 +6292,17 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
priv->direct_ssid, priv->direct_ssid_len);
direct_mask = 1;
} else if (!iwl3945_is_associated(priv) && priv->essid_len) {
+ IWL_DEBUG_SCAN
+ ("Kicking off one direct scan for '%s' when not associated\n",
+ iwl3945_escape_essid(priv->essid, priv->essid_len));
scan->direct_scan[0].id = WLAN_EID_SSID;
scan->direct_scan[0].len = priv->essid_len;
memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
direct_mask = 1;
- } else
+ } else {
+ IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
direct_mask = 0;
+ }
/* We don't build a direct scan probe request; the uCode will do
* that based on the direct_mask added to each channel entry */
@@ -6346,23 +6340,18 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
- if (direct_mask) {
- IWL_DEBUG_SCAN
- ("Initiating direct scan for %s.\n",
- iwl3945_escape_essid(priv->essid, priv->essid_len));
+ if (direct_mask)
scan->channel_count =
iwl3945_get_channels_for_scan(
priv, band, 1, /* active */
direct_mask,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
- } else {
- IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+ else
scan->channel_count =
iwl3945_get_channels_for_scan(
priv, band, 0, /* passive */
direct_mask,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
- }
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
scan->channel_count * sizeof(struct iwl3945_scan_channel);
@@ -7314,8 +7303,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
return;
}
- priv->only_active_channel = 0;
-
iwl3945_set_rate(priv);
mutex_unlock(&priv->mutex);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index d0bbcaaeb94c..883b42f7e998 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -4633,17 +4633,6 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
if (channels[i].flags & IEEE80211_CHAN_DISABLED)
continue;
- if (ieee80211_frequency_to_channel(channels[i].center_freq) ==
- le16_to_cpu(priv->active_rxon.channel)) {
- if (iwl_is_associated(priv)) {
- IWL_DEBUG_SCAN
- ("Skipping current channel %d\n",
- le16_to_cpu(priv->active_rxon.channel));
- continue;
- }
- } else if (priv->only_active_channel)
- continue;
-
scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq);
ch_info = iwl_get_channel_info(priv, band,
@@ -5824,11 +5813,15 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
priv->direct_ssid, priv->direct_ssid_len);
direct_mask = 1;
} else if (!iwl_is_associated(priv) && priv->essid_len) {
+ IWL_DEBUG_SCAN
+ ("Kicking off one direct scan for '%s' when not associated\n",
+ iwl4965_escape_essid(priv->essid, priv->essid_len));
scan->direct_scan[0].id = WLAN_EID_SSID;
scan->direct_scan[0].len = priv->essid_len;
memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
direct_mask = 1;
} else {
+ IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
direct_mask = 0;
}
@@ -5881,23 +5874,18 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
- if (direct_mask) {
- IWL_DEBUG_SCAN
- ("Initiating direct scan for %s.\n",
- iwl4965_escape_essid(priv->essid, priv->essid_len));
+ if (direct_mask)
scan->channel_count =
iwl4965_get_channels_for_scan(
priv, band, 1, /* active */
direct_mask,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
- } else {
- IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+ else
scan->channel_count =
iwl4965_get_channels_for_scan(
priv, band, 0, /* passive */
direct_mask,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
- }
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
scan->channel_count * sizeof(struct iwl4965_scan_channel);
@@ -7061,8 +7049,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
return;
}
- priv->only_active_channel = 0;
-
iwl4965_set_rate(priv);
mutex_unlock(&priv->mutex);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index e72c97a0d6c1..d448c9702a0f 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -298,7 +298,8 @@ static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
uint8_t *tlv; /* pointer into our current, growing TLV storage area */
lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
- bsstype, chan_list[0].channumber, chan_count);
+ bsstype, chan_list ? chan_list[0].channumber : -1,
+ chan_count);
/* create the fixed part for scan command */
scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
@@ -522,7 +523,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
if (*bytesleft >= sizeof(beaconsize)) {
/* Extract & convert beacon size from the command buffer */
- beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo));
+ beaconsize = get_unaligned_le16(*pbeaconinfo);
*bytesleft -= sizeof(beaconsize);
*pbeaconinfo += sizeof(beaconsize);
}
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 04c2638d75ad..9196825ed1b5 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -388,8 +388,15 @@ islpci_open(struct net_device *ndev)
netif_start_queue(ndev);
- /* Turn off carrier unless we know we have associated */
- netif_carrier_off(ndev);
+ /* Turn off carrier if in STA or Ad-hoc mode. It will be turned on
+ * once the firmware receives a trap of being associated
+ * (GEN_OID_LINKSTATE). In other modes (AP or WDS or monitor) we
+ * should just leave the carrier on as its expected the firmware
+ * won't send us a trigger. */
+ if (priv->iw_mode == IW_MODE_INFRA || priv->iw_mode == IW_MODE_ADHOC)
+ netif_carrier_off(ndev);
+ else
+ netif_carrier_on(ndev);
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index b41187af1306..560b9c73c0b9 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -363,7 +363,7 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
- rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
@@ -1308,7 +1308,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (value == LED_MODE_TXRX_ACTIVITY) {
rt2x00dev->led_qual.rt2x00dev = rt2x00dev;
- rt2x00dev->led_radio.type = LED_TYPE_ACTIVITY;
+ rt2x00dev->led_qual.type = LED_TYPE_ACTIVITY;
rt2x00dev->led_qual.led_dev.brightness_set =
rt2400pci_brightness_set;
rt2x00dev->led_qual.led_dev.blink_set =
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 5ade097ed45e..a5ed54b69262 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -370,7 +370,7 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
- rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
@@ -1485,7 +1485,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (value == LED_MODE_TXRX_ACTIVITY) {
rt2x00dev->led_qual.rt2x00dev = rt2x00dev;
- rt2x00dev->led_radio.type = LED_TYPE_ACTIVITY;
+ rt2x00dev->led_qual.type = LED_TYPE_ACTIVITY;
rt2x00dev->led_qual.led_dev.brightness_set =
rt2500pci_brightness_set;
rt2x00dev->led_qual.led_dev.blink_set =
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 6bb07b339325..fdbd0ef2be4b 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1394,7 +1394,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (value == LED_MODE_TXRX_ACTIVITY) {
rt2x00dev->led_qual.rt2x00dev = rt2x00dev;
- rt2x00dev->led_radio.type = LED_TYPE_ACTIVITY;
+ rt2x00dev->led_qual.type = LED_TYPE_ACTIVITY;
rt2x00dev->led_qual.led_dev.brightness_set =
rt2500usb_brightness_set;
rt2x00dev->led_qual.led_dev.blink_set =
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f8fe7a139a8a..b22c02737185 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -114,6 +114,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
return status;
rt2x00leds_led_radio(rt2x00dev, true);
+ rt2x00led_led_activity(rt2x00dev, true);
__set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);
@@ -157,6 +158,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
* Disable radio.
*/
rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF);
+ rt2x00led_led_activity(rt2x00dev, false);
rt2x00leds_led_radio(rt2x00dev, false);
}
@@ -1030,8 +1032,10 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
* Initialize the device.
*/
status = rt2x00dev->ops->lib->initialize(rt2x00dev);
- if (status)
- goto exit;
+ if (status) {
+ rt2x00queue_uninitialize(rt2x00dev);
+ return status;
+ }
__set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
@@ -1041,11 +1045,6 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
rt2x00rfkill_register(rt2x00dev);
return 0;
-
-exit:
- rt2x00lib_uninitialize(rt2x00dev);
-
- return status;
}
int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c
index 40c1f5c1b805..b362a1cf3f8d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
@@ -72,6 +72,21 @@ void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
}
}
+void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
+{
+ struct rt2x00_led *led = &rt2x00dev->led_qual;
+ unsigned int brightness;
+
+ if ((led->type != LED_TYPE_ACTIVITY) || !(led->flags & LED_REGISTERED))
+ return;
+
+ brightness = enabled ? LED_FULL : LED_OFF;
+ if (brightness != led->led_dev.brightness) {
+ led->led_dev.brightness_set(&led->led_dev, brightness);
+ led->led_dev.brightness = brightness;
+ }
+}
+
void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
{
struct rt2x00_led *led = &rt2x00dev->led_assoc;
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 5be32fffc74c..41ee02cd2825 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -185,6 +185,7 @@ static inline void rt2x00rfkill_resume(struct rt2x00_dev *rt2x00dev)
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi);
+void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_register(struct rt2x00_dev *rt2x00dev);
@@ -197,6 +198,11 @@ static inline void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev,
{
}
+static inline void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev,
+ bool enabled)
+{
+}
+
static inline void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 7867ec64bd2c..971af2546b59 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -314,13 +314,14 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
if (status) {
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
pci_dev->irq, status);
- return status;
+ goto exit;
}
return 0;
exit:
- rt2x00pci_uninitialize(rt2x00dev);
+ queue_for_each(rt2x00dev, queue)
+ rt2x00pci_free_queue_dma(rt2x00dev, queue);
return status;
}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 468a31c8c113..14bc7b281659 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2087,7 +2087,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (value == LED_MODE_SIGNAL_STRENGTH) {
rt2x00dev->led_qual.rt2x00dev = rt2x00dev;
- rt2x00dev->led_radio.type = LED_TYPE_QUALITY;
+ rt2x00dev->led_qual.type = LED_TYPE_QUALITY;
rt2x00dev->led_qual.led_dev.brightness_set =
rt61pci_brightness_set;
rt2x00dev->led_qual.led_dev.blink_set =
@@ -2366,6 +2366,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct queue_entry_priv_pci_tx *priv_tx;
struct skb_frame_desc *skbdesc;
unsigned int beacon_base;
u32 reg;
@@ -2373,21 +2374,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
if (unlikely(!intf->beacon))
return -ENOBUFS;
- /*
- * We need to append the descriptor in front of the
- * beacon frame.
- */
- if (skb_headroom(skb) < intf->beacon->queue->desc_size) {
- if (pskb_expand_head(skb, intf->beacon->queue->desc_size,
- 0, GFP_ATOMIC))
- return -ENOMEM;
- }
-
- /*
- * Add the descriptor in front of the skb.
- */
- skb_push(skb, intf->beacon->queue->desc_size);
- memset(skb->data, 0, intf->beacon->queue->desc_size);
+ priv_tx = intf->beacon->priv_data;
+ memset(priv_tx->desc, 0, intf->beacon->queue->desc_size);
/*
* Fill in skb descriptor
@@ -2395,9 +2383,9 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
- skbdesc->data = skb->data + intf->beacon->queue->desc_size;
- skbdesc->data_len = skb->len - intf->beacon->queue->desc_size;
- skbdesc->desc = skb->data;
+ skbdesc->data = skb->data;
+ skbdesc->data_len = skb->len;
+ skbdesc->desc = priv_tx->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon;
@@ -2425,7 +2413,10 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
*/
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
- skb->data, skb->len);
+ skbdesc->desc, skbdesc->desc_len);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base + skbdesc->desc_len,
+ skbdesc->data, skbdesc->data_len);
rt61pci_kick_tx_queue(rt2x00dev, control->queue);
return 0;
@@ -2490,7 +2481,7 @@ static const struct data_queue_desc rt61pci_queue_tx = {
static const struct data_queue_desc rt61pci_queue_bcn = {
.entry_num = 4 * BEACON_ENTRIES,
- .data_size = MGMT_FRAME_SIZE,
+ .data_size = 0, /* No DMA required for beacons */
.desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx),
};
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index a9efe25f1ea7..da19a3a91f4d 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1647,7 +1647,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (value == LED_MODE_SIGNAL_STRENGTH) {
rt2x00dev->led_qual.rt2x00dev = rt2x00dev;
- rt2x00dev->led_radio.type = LED_TYPE_QUALITY;
+ rt2x00dev->led_qual.type = LED_TYPE_QUALITY;
rt2x00dev->led_qual.led_dev.brightness_set =
rt73usb_brightness_set;
rt2x00dev->led_qual.led_dev.blink_set =
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index bced3fe1cf8a..883af891ebfb 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -768,41 +768,17 @@ static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst,
/* General routines for STRIP */
/*
- * get_baud returns the current baud rate, as one of the constants defined in
- * termbits.h
- * If the user has issued a baud rate override using the 'setserial' command
- * and the logical current rate is set to 38.4, then the true baud rate
- * currently in effect (57.6 or 115.2) is returned.
- */
-static unsigned int get_baud(struct tty_struct *tty)
-{
- if (!tty || !tty->termios)
- return (0);
- if ((tty->termios->c_cflag & CBAUD) == B38400 && tty->driver_data) {
- struct async_struct *info =
- (struct async_struct *) tty->driver_data;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- return (B57600);
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- return (B115200);
- }
- return (tty->termios->c_cflag & CBAUD);
-}
-
-/*
* set_baud sets the baud rate to the rate defined by baudcode
- * Note: The rate B38400 should be avoided, because the user may have
- * issued a 'setserial' speed override to map that to a different speed.
- * We could achieve a true rate of 38400 if we needed to by cancelling
- * any user speed override that is in place, but that might annoy the
- * user, so it is simplest to just avoid using 38400.
*/
-static void set_baud(struct tty_struct *tty, unsigned int baudcode)
+static void set_baud(struct tty_struct *tty, speed_t baudrate)
{
- struct ktermios old_termios = *(tty->termios);
- tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */
- tty->termios->c_cflag |= baudcode; /* Set the new baud setting */
- tty->driver->set_termios(tty, &old_termios);
+ struct ktermios old_termios;
+
+ mutex_lock(&tty->termios_mutex);
+ old_termios =*(tty->termios);
+ tty_encode_baud_rate(tty, baudrate, baudrate);
+ tty->ops->set_termios(tty, &old_termios);
+ mutex_unlock(&tty->termios_mutex);
}
/*
@@ -1217,7 +1193,7 @@ static void ResetRadio(struct strip *strip_info)
strip_info->watchdog_doreset = jiffies + 1 * HZ;
/* If the user has selected a baud rate above 38.4 see what magic we have to do */
- if (strip_info->user_baud > B38400) {
+ if (strip_info->user_baud > 38400) {
/*
* Subtle stuff: Pay attention :-)
* If the serial port is currently at the user's selected (>38.4) rate,
@@ -1227,17 +1203,17 @@ static void ResetRadio(struct strip *strip_info)
* issued the ATS304 command last time through, so this time we restore
* the user's selected rate and issue the normal starmode reset string.
*/
- if (strip_info->user_baud == get_baud(tty)) {
+ if (strip_info->user_baud == tty_get_baud_rate(tty)) {
static const char b0[] = "ate0q1s304=57600\r";
static const char b1[] = "ate0q1s304=115200\r";
static const StringDescriptor baudstring[2] =
{ {b0, sizeof(b0) - 1}
, {b1, sizeof(b1) - 1}
};
- set_baud(tty, B19200);
- if (strip_info->user_baud == B57600)
+ set_baud(tty, 19200);
+ if (strip_info->user_baud == 57600)
s = baudstring[0];
- else if (strip_info->user_baud == B115200)
+ else if (strip_info->user_baud == 115200)
s = baudstring[1];
else
s = baudstring[1]; /* For now */
@@ -1245,7 +1221,7 @@ static void ResetRadio(struct strip *strip_info)
set_baud(tty, strip_info->user_baud);
}
- tty->driver->write(tty, s.string, s.length);
+ tty->ops->write(tty, s.string, s.length);
#ifdef EXT_COUNTERS
strip_info->tx_ebytes += s.length;
#endif
@@ -1267,7 +1243,7 @@ static void strip_write_some_more(struct tty_struct *tty)
if (strip_info->tx_left > 0) {
int num_written =
- tty->driver->write(tty, strip_info->tx_head,
+ tty->ops->write(tty, strip_info->tx_head,
strip_info->tx_left);
strip_info->tx_left -= num_written;
strip_info->tx_head += num_written;
@@ -2457,7 +2433,7 @@ static int strip_open_low(struct net_device *dev)
strip_info->working = FALSE;
strip_info->firmware_level = NoStructure;
strip_info->next_command = CompatibilityCommand;
- strip_info->user_baud = get_baud(strip_info->tty);
+ strip_info->user_baud = tty_get_baud_rate(strip_info->tty);
printk(KERN_INFO "%s: Initializing Radio.\n",
strip_info->dev->name);
@@ -2632,6 +2608,13 @@ static int strip_open(struct tty_struct *tty)
return -EEXIST;
/*
+ * We need a write method.
+ */
+
+ if (tty->ops->write == NULL || tty->ops->set_termios == NULL)
+ return -EOPNOTSUPP;
+
+ /*
* OK. Find a free STRIP channel to use.
*/
if ((strip_info = strip_alloc()) == NULL)
@@ -2652,8 +2635,7 @@ static int strip_open(struct tty_struct *tty)
tty->disc_data = strip_info;
tty->receive_room = 65536;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/*
* Restore default settings
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 03384a43186b..49ae97003952 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -908,9 +908,9 @@ static void wv_psa_show(psa_t * p)
p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5],
p->psa_call_code[6], p->psa_call_code[7]);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+ printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n",
p->psa_reserved[0],
- p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]);
+ p->psa_reserved[1]);
#endif /* DEBUG_SHOW_UNUSED */
printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index baf74015751c..b584c0ecc62d 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1074,11 +1074,9 @@ wv_psa_show(psa_t * p)
p->psa_call_code[6],
p->psa_call_code[7]);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+ printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n",
p->psa_reserved[0],
- p->psa_reserved[1],
- p->psa_reserved[2],
- p->psa_reserved[3]);
+ p->psa_reserved[1]);
#endif /* DEBUG_SHOW_UNUSED */
printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index e34675c2f8fc..12e24f04dddf 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -545,11 +545,11 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
* be padded. Unaligned access might also happen if the length_info
* structure is not present.
*/
- if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG))
+ if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG)
{
unsigned int l, k, n;
for (i = 0, l = 0;; i++) {
- k = le16_to_cpu(get_unaligned(&length_info->length[i]));
+ k = get_unaligned_le16(&length_info->length[i]);
if (k == 0)
return;
n = l+k;
@@ -889,9 +889,13 @@ static void tx_urb_complete(struct urb *urb)
}
free_urb:
skb = (struct sk_buff *)urb->context;
- zd_mac_tx_to_dev(skb, urb->status);
+ /*
+ * grab 'usb' pointer before handing off the skb (since
+ * it might be freed by zd_mac_tx_to_dev or mac80211)
+ */
cb = (struct zd_tx_skb_control_block *)skb->cb;
usb = &zd_hw_mac(cb->hw)->chip.usb;
+ zd_mac_tx_to_dev(skb, urb->status);
free_tx_urb(usb, urb);
tx_dec_submitted_urbs(usb);
return;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index e62018a36133..8bddff150c70 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1803,7 +1803,7 @@ static void __exit netif_exit(void)
if (is_initial_xendomain())
return;
- return xenbus_unregister_driver(&netfront);
+ xenbus_unregister_driver(&netfront);
}
module_exit(netif_exit);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 24640726f8bb..57e1f495b9fc 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1062,7 +1062,7 @@ static int yellowfin_rx(struct net_device *dev)
buf_addr = rx_skb->data;
data_size = (le32_to_cpu(desc->dbdma_cmd) -
le32_to_cpu(desc->result_status)) & 0xffff;
- frame_status = le16_to_cpu(get_unaligned((__le16*)&(buf_addr[data_size - 2])));
+ frame_status = get_unaligned_le16(&(buf_addr[data_size - 2]));
if (yellowfin_debug > 4)
printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
frame_status);
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index e07492be1f4a..208dd12825bc 100644
--- a/drivers/nubus/proc.c
+++ b/drivers/nubus/proc.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/nubus.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -28,38 +29,36 @@
#include <asm/byteorder.h>
static int
-get_nubus_dev_info(char *buf, char **start, off_t pos, int count)
+nubus_devices_proc_show(struct seq_file *m, void *v)
{
struct nubus_dev *dev = nubus_devices;
- off_t at = 0;
- int len, cnt;
- cnt = 0;
- while (dev && count > cnt) {
- len = sprintf(buf, "%x\t%04x %04x %04x %04x",
+ while (dev) {
+ seq_printf(m, "%x\t%04x %04x %04x %04x",
dev->board->slot,
dev->category,
dev->type,
dev->dr_sw,
dev->dr_hw);
- len += sprintf(buf+len,
- "\t%08lx",
- dev->board->slot_addr);
- buf[len++] = '\n';
- at += len;
- if (at >= pos) {
- if (!*start) {
- *start = buf + (pos - (at - len));
- cnt = at - pos;
- } else
- cnt += len;
- buf += len;
- }
+ seq_printf(m, "\t%08lx\n", dev->board->slot_addr);
dev = dev->next;
}
- return (count > cnt) ? cnt : count;
+ return 0;
+}
+
+static int nubus_devices_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, nubus_devices_proc_show, NULL);
}
+static const struct file_operations nubus_devices_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = nubus_devices_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static struct proc_dir_entry *proc_bus_nubus_dir;
static void nubus_proc_subdir(struct nubus_dev* dev,
@@ -171,8 +170,7 @@ void __init nubus_proc_init(void)
{
if (!MACH_IS_MAC)
return;
- proc_bus_nubus_dir = proc_mkdir("nubus", proc_bus);
- create_proc_info_entry("devices", 0, proc_bus_nubus_dir,
- get_nubus_dev_info);
+ proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL);
+ proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops);
proc_bus_nubus_add_devices();
}
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 9bd7c4a31253..23ffb7c0caf2 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -65,6 +65,9 @@ struct property *of_find_property(const struct device_node *np,
{
struct property *pp;
+ if (!np)
+ return NULL;
+
read_lock(&devtree_lock);
for (pp = np->properties; pp != 0; pp = pp->next) {
if (of_prop_cmp(pp->name, name) == 0) {
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index efcbf4b4579f..2450b3a393ff 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -27,7 +27,7 @@
#include "buffer_sync.h"
#include "oprof.h"
-DEFINE_PER_CPU_SHARED_ALIGNED(struct oprofile_cpu_buffer, cpu_buffer);
+DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
static void wq_sync_buffer(struct work_struct *work);
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index 13588174311d..c3e366b52261 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -46,7 +46,7 @@ struct oprofile_cpu_buffer {
unsigned long sample_invalid_eip;
int cpu;
struct delayed_work work;
-} ____cacheline_aligned;
+};
DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c
index 558420bc9f88..821369135369 100644
--- a/drivers/parisc/asp.c
+++ b/drivers/parisc/asp.c
@@ -88,7 +88,7 @@ asp_init_chip(struct parisc_device *dev)
ret = -EBUSY;
dev->irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
if (dev->irq < 0) {
- printk(KERN_ERR "%s(): cannot get GSC irq\n", __FUNCTION__);
+ printk(KERN_ERR "%s(): cannot get GSC irq\n", __func__);
goto out;
}
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 62db3c3fe4dc..b30e38f3a50d 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -359,7 +359,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE);
DBG_RES("%s() size: %d pages_needed %d\n",
- __FUNCTION__, size, pages_needed);
+ __func__, size, pages_needed);
/*
** "seek and ye shall find"...praying never hurts either...
@@ -395,16 +395,16 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
#endif
} else {
panic("%s: %s() Too many pages to map. pages_needed: %u\n",
- __FILE__, __FUNCTION__, pages_needed);
+ __FILE__, __func__, pages_needed);
}
panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__,
- __FUNCTION__);
+ __func__);
resource_found:
DBG_RES("%s() res_idx %d res_hint: %d\n",
- __FUNCTION__, res_idx, ioc->res_hint);
+ __func__, res_idx, ioc->res_hint);
#ifdef CCIO_SEARCH_TIME
{
@@ -450,7 +450,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
BUG_ON(pages_mapped > BITS_PER_LONG);
DBG_RES("%s(): res_idx: %d pages_mapped %d\n",
- __FUNCTION__, res_idx, pages_mapped);
+ __func__, res_idx, pages_mapped);
#ifdef CCIO_MAP_STATS
ioc->used_pages -= pages_mapped;
@@ -474,7 +474,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
#endif
} else {
panic("%s:%s() Too many pages to unmap.\n", __FILE__,
- __FUNCTION__);
+ __func__);
}
}
@@ -775,7 +775,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
pdir_start = &(ioc->pdir_base[idx]);
DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n",
- __FUNCTION__, addr, (long)iovp | offset, size);
+ __func__, addr, (long)iovp | offset, size);
/* If not cacheline aligned, force SAFE_DMA on the whole mess */
if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
@@ -820,7 +820,7 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
ioc = GET_IOC(dev);
DBG_RUN("%s() iovp 0x%lx/%x\n",
- __FUNCTION__, (long)iova, size);
+ __func__, (long)iova, size);
iova ^= offset; /* clear offset bits */
size += offset;
@@ -922,7 +922,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
BUG_ON(!dev);
ioc = GET_IOC(dev);
- DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+ DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
/* Fast path single entry scatterlists. */
if (nents == 1) {
@@ -966,7 +966,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
BUG_ON(coalesced != filled);
- DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+ DBG_RUN_SG("%s() DONE %d mappings\n", __func__, filled);
for (i = 0; i < filled; i++)
current_len += sg_dma_len(sglist + i);
@@ -995,7 +995,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
ioc = GET_IOC(dev);
DBG_RUN_SG("%s() START %d entries, %08lx,%x\n",
- __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);
+ __func__, nents, sg_virt_addr(sglist), sglist->length);
#ifdef CCIO_MAP_STATS
ioc->usg_calls++;
@@ -1011,7 +1011,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
++sglist;
}
- DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents);
+ DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents);
}
static struct hppa_dma_ops ccio_ops = {
@@ -1225,7 +1225,7 @@ static int
ccio_get_iotlb_size(struct parisc_device *dev)
{
if (dev->spa_shift == 0) {
- panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__);
+ panic("%s() : Can't determine I/O TLB size.\n", __func__);
}
return (1 << dev->spa_shift);
}
@@ -1315,7 +1315,7 @@ ccio_ioc_init(struct ioc *ioc)
BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT));
DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n",
- __FUNCTION__, ioc->ioc_regs,
+ __func__, ioc->ioc_regs,
(unsigned long) num_physpages >> (20 - PAGE_SHIFT),
iova_space_size>>20,
iov_order + PAGE_SHIFT);
@@ -1323,7 +1323,7 @@ ccio_ioc_init(struct ioc *ioc)
ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->pdir_size));
if(NULL == ioc->pdir_base) {
- panic("%s() could not allocate I/O Page Table\n", __FUNCTION__);
+ panic("%s() could not allocate I/O Page Table\n", __func__);
}
memset(ioc->pdir_base, 0, ioc->pdir_size);
@@ -1332,12 +1332,12 @@ ccio_ioc_init(struct ioc *ioc)
/* resource map size dictated by pdir_size */
ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;
- DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);
+ DBG_INIT("%s() res_size 0x%x\n", __func__, ioc->res_size);
ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->res_size));
if(NULL == ioc->res_map) {
- panic("%s() could not allocate resource map\n", __FUNCTION__);
+ panic("%s() could not allocate resource map\n", __func__);
}
memset(ioc->res_map, 0, ioc->res_size);
@@ -1409,7 +1409,7 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr)
result = insert_resource(&iomem_resource, res);
if (result < 0) {
printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n",
- __FUNCTION__, res->start, res->end);
+ __func__, res->start, res->end);
}
}
@@ -1551,8 +1551,7 @@ static int __init ccio_probe(struct parisc_device *dev)
{
int i;
struct ioc *ioc, **ioc_p = &ioc_list;
- struct proc_dir_entry *info_entry, *bitmap_entry;
-
+
ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL);
if (ioc == NULL) {
printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
@@ -1580,13 +1579,10 @@ static int __init ccio_probe(struct parisc_device *dev)
HBA_DATA(dev->dev.platform_data)->iommu = ioc;
if (ioc_count == 0) {
- info_entry = create_proc_entry(MODULE_NAME, 0, proc_runway_root);
- if (info_entry)
- info_entry->proc_fops = &ccio_proc_info_fops;
-
- bitmap_entry = create_proc_entry(MODULE_NAME"-bitmap", 0, proc_runway_root);
- if (bitmap_entry)
- bitmap_entry->proc_fops = &ccio_proc_bitmap_fops;
+ proc_create(MODULE_NAME, 0, proc_runway_root,
+ &ccio_proc_info_fops);
+ proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root,
+ &ccio_proc_bitmap_fops);
}
ioc_count++;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index d9c6322a721b..fd56128525d1 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -180,7 +180,7 @@ static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where,
void __iomem *base_addr = d->hba.base_addr;
unsigned long flags;
- DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where,
+ DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where,
size);
spin_lock_irqsave(&d->dinosaur_pen, flags);
@@ -215,7 +215,7 @@ static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where,
void __iomem *base_addr = d->hba.base_addr;
unsigned long flags;
- DBG("%s: %p, %d, %d, %d\n", __FUNCTION__, base_addr, devfn, where,
+ DBG("%s: %p, %d, %d, %d\n", __func__, base_addr, devfn, where,
size);
spin_lock_irqsave(&d->dinosaur_pen, flags);
@@ -301,7 +301,7 @@ static void dino_disable_irq(unsigned int irq)
struct dino_device *dino_dev = irq_desc[irq].chip_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
- DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq);
+ DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
/* Clear the matching bit in the IMR register */
dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq));
@@ -314,7 +314,7 @@ static void dino_enable_irq(unsigned int irq)
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
u32 tmp;
- DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq);
+ DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
/*
** clear pending IRQ bits
@@ -340,7 +340,7 @@ static void dino_enable_irq(unsigned int irq)
tmp = __raw_readl(dino_dev->hba.base_addr+DINO_ILR);
if (tmp & DINO_MASK_IRQ(local_irq)) {
DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
- __FUNCTION__, tmp);
+ __func__, tmp);
gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
}
}
@@ -388,7 +388,7 @@ ilr_again:
int local_irq = __ffs(mask);
int irq = dino_dev->global_irq[local_irq];
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
- __FUNCTION__, irq, intr_dev, mask);
+ __func__, irq, intr_dev, mask);
__do_IRQ(irq);
mask &= ~(1 << local_irq);
} while (mask);
@@ -566,7 +566,7 @@ dino_fixup_bus(struct pci_bus *bus)
int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
- __FUNCTION__, bus, bus->secondary,
+ __func__, bus, bus->secondary,
bus->bridge->platform_data);
/* Firmware doesn't set up card-mode dino, so we have to */
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index 1b3e3fd12d95..f7d088b897ee 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -112,7 +112,7 @@ static void gsc_asic_disable_irq(unsigned int irq)
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
- DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __FUNCTION__, irq,
+ DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
irq_dev->name, imr);
/* Disable the IRQ line by clearing the bit in the IMR */
@@ -127,7 +127,7 @@ static void gsc_asic_enable_irq(unsigned int irq)
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
- DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __FUNCTION__, irq,
+ DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
irq_dev->name, imr);
/* Enable the IRQ line by setting the bit in the IMR */
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index cb3d28176129..bee510098ce8 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -193,7 +193,7 @@ lasi_init_chip(struct parisc_device *dev)
dev->irq = gsc_alloc_irq(&gsc_irq);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n",
- __FUNCTION__);
+ __func__);
kfree(lasi);
return -EBUSY;
}
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 66ce61048361..a28c8946deaa 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -377,12 +377,12 @@ static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int
/* original - Generate config cycle on broken elroy
with risk we will miss PCI bus errors. */
*data = lba_rd_cfg(d, tok, pos, size);
- DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data);
+ DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __func__, tok, pos, *data);
return 0;
}
if (LBA_SKIP_PROBE(d) && !lba_device_present(bus->secondary, devfn, d)) {
- DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __FUNCTION__, tok, pos);
+ DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __func__, tok, pos);
/* either don't want to look or know device isn't present. */
*data = ~0U;
return(0);
@@ -398,7 +398,7 @@ static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int
case 2: *data = READ_REG16(data_reg + (pos & 2)); break;
case 4: *data = READ_REG32(data_reg); break;
}
- DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos, *data);
+ DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __func__, tok, pos, *data);
return 0;
}
@@ -441,16 +441,16 @@ static int elroy_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int
if (!LBA_SKIP_PROBE(d)) {
/* Original Workaround */
lba_wr_cfg(d, tok, pos, (u32) data, size);
- DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __FUNCTION__, tok, pos,data);
+ DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __func__, tok, pos,data);
return 0;
}
if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d))) {
- DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __FUNCTION__, tok, pos,data);
+ DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __func__, tok, pos,data);
return 1; /* New Workaround */
}
- DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __FUNCTION__, tok, pos, data);
+ DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __func__, tok, pos, data);
/* Basic Algorithm */
LBA_CFG_ADDR_SETUP(d, tok | pos);
@@ -521,7 +521,7 @@ static int mercury_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, i
if ((pos > 255) || (devfn > 255))
return -EINVAL;
- DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __FUNCTION__, tok, pos, data);
+ DBG_CFG("%s(%x+%2x) <- 0x%x (c)\n", __func__, tok, pos, data);
LBA_CFG_TR4_ADDR_SETUP(d, tok | pos);
switch(size) {
@@ -890,7 +890,7 @@ LBA_PORT_IN(32, 0)
#define LBA_PORT_OUT(size, mask) \
static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
{ \
- DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
+ DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __func__, d, addr, val); \
WRITE_REG##size(val, astro_iop_base + addr); \
if (LBA_DEV(d)->hw_rev < 3) \
lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
@@ -932,7 +932,7 @@ static struct pci_port_ops lba_astro_port_ops = {
static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \
{ \
u##size t; \
- DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
+ DBG_PORT("%s(0x%p, 0x%x) ->", __func__, l, addr); \
t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \
DBG_PORT(" 0x%x\n", t); \
return (t); \
@@ -948,7 +948,7 @@ LBA_PORT_IN(32, 0)
static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \
{ \
void __iomem *where = PIOP_TO_GMMIO(LBA_DEV(l), addr); \
- DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
+ DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __func__, l, addr, val); \
WRITE_REG##size(val, where); \
/* flush the I/O down to the elroy at least */ \
lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \
@@ -1584,7 +1584,7 @@ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
WARN_ON((ibase & 0x001fffff) != 0);
WARN_ON((imask & 0x001fffff) != 0);
- DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
+ DBG("%s() ibase 0x%x imask 0x%x\n", __func__, ibase, imask);
WRITE_REG32( imask, base_addr + LBA_IMASK);
WRITE_REG32( ibase, base_addr + LBA_IBASE);
iounmap(base_addr);
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 703b85edb004..f9b12664f9fb 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -569,7 +569,7 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d
default:
printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
- __FUNCTION__, lcd_info.model);
+ __func__, lcd_info.model);
return 1;
}
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 8c4d2c13d5f2..bc73b96346ff 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -384,7 +384,7 @@ sba_search_bitmap(struct ioc *ioc, struct device *dev,
}
mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt;
- DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
+ DBG_RES("%s() o %ld %p", __func__, o, res_ptr);
while(res_ptr < res_end)
{
DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr);
@@ -454,7 +454,7 @@ sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
#endif
DBG_RES("%s(%x) %d -> %lx hint %x/%x\n",
- __FUNCTION__, size, pages_needed, pide,
+ __func__, size, pages_needed, pide,
(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
ioc->res_bitshift );
@@ -497,7 +497,7 @@ sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1));
DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
- __FUNCTION__, (uint) iova, size,
+ __func__, (uint) iova, size,
bits_not_wanted, m, pide, res_ptr, *res_ptr);
#ifdef SBA_COLLECT_STATS
@@ -740,7 +740,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
iovp = (dma_addr_t) pide << IOVP_SHIFT;
DBG_RUN("%s() 0x%p -> 0x%lx\n",
- __FUNCTION__, addr, (long) iovp | offset);
+ __func__, addr, (long) iovp | offset);
pdir_start = &(ioc->pdir_base[pide]);
@@ -798,7 +798,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
unsigned long flags;
dma_addr_t offset;
- DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size);
+ DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size);
ioc = GET_IOC(dev);
offset = iova & ~IOVP_MASK;
@@ -937,7 +937,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
int coalesced, filled = 0;
unsigned long flags;
- DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+ DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
ioc = GET_IOC(dev);
@@ -998,7 +998,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
spin_unlock_irqrestore(&ioc->res_lock, flags);
- DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+ DBG_RUN_SG("%s() DONE %d mappings\n", __func__, filled);
return filled;
}
@@ -1023,7 +1023,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
#endif
DBG_RUN_SG("%s() START %d entries, %p,%x\n",
- __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);
+ __func__, nents, sg_virt_addr(sglist), sglist->length);
ioc = GET_IOC(dev);
@@ -1047,7 +1047,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
++sglist;
}
- DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents);
+ DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents);
#ifdef ASSERT_PDIR_SANITY
spin_lock_irqsave(&ioc->res_lock, flags);
@@ -1118,7 +1118,7 @@ sba_alloc_pdir(unsigned int pdir_size)
pdir_base = __get_free_pages(GFP_KERNEL, pdir_order);
if (NULL == (void *) pdir_base) {
panic("%s() could not allocate I/O Page Table\n",
- __FUNCTION__);
+ __func__);
}
/* If this is not PA8700 (PCX-W2)
@@ -1261,7 +1261,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
- __FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
+ __func__, ioc->ioc_hpa, iova_space_size >> 20,
iov_order + PAGE_SHIFT);
ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL,
@@ -1272,7 +1272,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
memset(ioc->pdir_base, 0, ioc->pdir_size);
DBG_INIT("%s() pdir %p size %x\n",
- __FUNCTION__, ioc->pdir_base, ioc->pdir_size);
+ __func__, ioc->pdir_base, ioc->pdir_size);
#ifdef SBA_HINT_SUPPORT
ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
@@ -1354,7 +1354,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
if (agp_found && sba_reserve_agpgart) {
printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
- __FUNCTION__, (iova_space_size/2) >> 20);
+ __func__, (iova_space_size/2) >> 20);
ioc->pdir_size /= 2;
ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
}
@@ -1406,7 +1406,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
DBG_INIT("%s() hpa 0x%lx mem %ldMB IOV %dMB (%d bits)\n",
- __FUNCTION__,
+ __func__,
ioc->ioc_hpa,
(unsigned long) num_physpages >> (20 - PAGE_SHIFT),
iova_space_size>>20,
@@ -1415,7 +1415,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
ioc->pdir_base = sba_alloc_pdir(pdir_size);
DBG_INIT("%s() pdir %p size %x\n",
- __FUNCTION__, ioc->pdir_base, pdir_size);
+ __func__, ioc->pdir_base, pdir_size);
#ifdef SBA_HINT_SUPPORT
/* FIXME : DMA HINTs not used */
@@ -1443,7 +1443,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
#endif
DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
- __FUNCTION__, ioc->ibase, ioc->imask);
+ __func__, ioc->ibase, ioc->imask);
/*
** FIXME: Hint registers are programmed with default hint
@@ -1470,7 +1470,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
ioc->ibase = 0; /* used by SBA_IOVA and related macros */
- DBG_INIT("%s() DONE\n", __FUNCTION__);
+ DBG_INIT("%s() DONE\n", __func__);
}
@@ -1544,7 +1544,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
if (!IS_PLUTO(sba_dev->dev)) {
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
- __FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
+ __func__, sba_dev->sba_hpa, ioc_ctl);
ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE);
ioc_ctl |= IOC_CTRL_DD | IOC_CTRL_D4 | IOC_CTRL_TC;
/* j6700 v1.6 firmware sets 0x294f */
@@ -1675,7 +1675,7 @@ sba_common_init(struct sba_device *sba_dev)
res_size >>= 3; /* convert bit count to byte count */
DBG_INIT("%s() res_size 0x%x\n",
- __FUNCTION__, res_size);
+ __func__, res_size);
sba_dev->ioc[i].res_size = res_size;
sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
@@ -1688,7 +1688,7 @@ sba_common_init(struct sba_device *sba_dev)
if (NULL == sba_dev->ioc[i].res_map)
{
panic("%s:%s() could not allocate resource map\n",
- __FILE__, __FUNCTION__ );
+ __FILE__, __func__ );
}
memset(sba_dev->ioc[i].res_map, 0, res_size);
@@ -1725,7 +1725,7 @@ sba_common_init(struct sba_device *sba_dev)
#endif
DBG_INIT("%s() %d res_map %x %p\n",
- __FUNCTION__, i, res_size, sba_dev->ioc[i].res_map);
+ __func__, i, res_size, sba_dev->ioc[i].res_map);
}
spin_lock_init(&sba_dev->sba_lock);
@@ -1895,7 +1895,9 @@ sba_driver_callback(struct parisc_device *dev)
int i;
char *version;
void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE);
- struct proc_dir_entry *info_entry, *bitmap_entry, *root;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *root;
+#endif
sba_dump_ranges(sba_addr);
@@ -1973,14 +1975,8 @@ sba_driver_callback(struct parisc_device *dev)
break;
}
- info_entry = create_proc_entry("sba_iommu", 0, root);
- bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root);
-
- if (info_entry)
- info_entry->proc_fops = &sba_proc_fops;
-
- if (bitmap_entry)
- bitmap_entry->proc_fops = &sba_proc_bitmap_fops;
+ proc_create("sba_iommu", 0, root, &sba_proc_fops);
+ proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops);
#endif
parisc_vmerge_boundary = IOVP_SIZE;
diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c
index 813c2c24ab1e..892a83bbe73d 100644
--- a/drivers/parisc/wax.c
+++ b/drivers/parisc/wax.c
@@ -93,7 +93,7 @@ wax_init_chip(struct parisc_device *dev)
dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n",
- __FUNCTION__);
+ __func__);
kfree(wax);
return -EBUSY;
}
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 54a6ef72906e..0338b0912674 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -76,7 +76,7 @@ int parport_wait_event (struct parport *port, signed long timeout)
semaphore. */
return 1;
- init_timer (&timer);
+ init_timer_on_stack(&timer);
timer.expires = jiffies + timeout;
timer.function = timeout_waiting_on_port;
port_from_cookie[port->number % PARPORT_MAX] = port;
@@ -88,6 +88,8 @@ int parport_wait_event (struct parport *port, signed long timeout)
/* Timed out. */
ret = 1;
+ destroy_timer_on_stack(&timer);
+
return ret;
}
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 0e77ae2b71a0..e6a7e847ee80 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -365,11 +365,11 @@ static int __devinit parport_init_chip(struct parisc_device *dev)
if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) {
/* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */
- printk("%s: initialize bidirectional-mode.\n", __FUNCTION__);
+ printk("%s: initialize bidirectional-mode.\n", __func__);
parport_writeb ( (0x10 + 0x20), port + 4);
} else {
- printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__);
+ printk("%s: enhanced parport-modes not supported.\n", __func__);
}
p = parport_gsc_probe_port(port, 0, dev->irq,
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index a85808938205..e0c2a4584ec6 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1415,7 +1415,7 @@ static void __devinit winbond_check(int io, int key)
{
int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without key */
@@ -1449,7 +1449,7 @@ static void __devinit winbond_check2(int io,int key)
{
int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without the key */
@@ -1482,7 +1482,7 @@ static void __devinit smsc_check(int io, int key)
{
int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without the key */
@@ -1547,7 +1547,7 @@ static void __devinit detect_and_report_it87(void)
u8 r;
if (verbose_probing)
printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
- if (!request_region(0x2e, 1, __FUNCTION__))
+ if (!request_region(0x2e, 1, __func__))
return;
outb(0x87, 0x2e);
outb(0x01, 0x2e);
@@ -3082,6 +3082,7 @@ static struct pci_driver parport_pc_pci_driver;
static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;}
#endif /* CONFIG_PCI */
+#ifdef CONFIG_PNP
static const struct pnp_device_id parport_pc_pnp_tbl[] = {
/* Standard LPT Printer Port */
@@ -3148,6 +3149,9 @@ static struct pnp_driver parport_pc_pnp_driver = {
.remove = parport_pc_pnp_remove,
};
+#else
+static struct pnp_driver parport_pc_pnp_driver;
+#endif /* CONFIG_PNP */
static int __devinit parport_pc_platform_probe(struct platform_device *pdev)
{
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index f14267e197dd..8264a7680435 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -93,11 +93,10 @@ struct controller {
u8 slot_device_offset;
u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */
u8 slot_bus; /* Bus where the slots handled by this controller sit */
- u8 ctrlcap;
+ u32 slot_cap;
u8 cap_base;
struct timer_list poll_timer;
volatile int cmd_busy;
- spinlock_t lock;
};
#define INT_BUTTON_IGNORE 0
@@ -137,13 +136,13 @@ struct controller {
#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)
-#define MRL_SENS(cap) (cap & MRL_SENS_PRSN)
-#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)
-#define EMI(cap) (cap & EMI_PRSN)
+#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN)
+#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN)
+#define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN)
+#define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN)
+#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN)
+#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP)
+#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN)
extern int pciehp_sysfs_enable_slot(struct slot *slot);
extern int pciehp_sysfs_disable_slot(struct slot *slot);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index aee19f013d84..43d8ddb2d679 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -41,6 +41,7 @@ int pciehp_debug;
int pciehp_poll_mode;
int pciehp_poll_time;
int pciehp_force;
+int pciehp_slot_with_bus;
struct workqueue_struct *pciehp_wq;
#define DRIVER_VERSION "0.4"
@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);
module_param(pciehp_poll_mode, bool, 0644);
module_param(pciehp_poll_time, int, 0644);
module_param(pciehp_force, bool, 0644);
+module_param(pciehp_slot_with_bus, bool, 0644);
MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name");
#define PCIE_MODULE_NAME "pciehp"
@@ -193,8 +196,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
static void make_slot_name(struct slot *slot)
{
- snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
- slot->bus, slot->number);
+ if (pciehp_slot_with_bus)
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+ else
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d",
+ slot->number);
}
static int init_slots(struct controller *ctrl)
@@ -251,7 +258,7 @@ static int init_slots(struct controller *ctrl)
goto error_info;
}
/* create additional sysfs entries */
- if (EMI(ctrl->ctrlcap)) {
+ if (EMI(ctrl)) {
retval = sysfs_create_file(&hotplug_slot->kobj,
&hotplug_slot_attr_lock.attr);
if (retval) {
@@ -284,7 +291,7 @@ static void cleanup_slots(struct controller *ctrl)
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))
+ if (EMI(ctrl))
sysfs_remove_file(&slot->hotplug_slot->kobj,
&hotplug_slot_attr_lock.attr);
cancel_delayed_work(&slot->work);
@@ -305,7 +312,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
hotplug_slot->info->attention_status = status;
- if (ATTN_LED(slot->ctrl->ctrlcap))
+ if (ATTN_LED(slot->ctrl))
slot->hpc_ops->set_attention_status(slot, status);
return 0;
@@ -472,7 +479,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
if (rc) /* -ENODEV: shouldn't happen, but deal with it */
value = 0;
}
- if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
+ if ((POWER_CTRL(ctrl)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
if (rc)
goto err_out_free_ctrl_slot;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 0c481f7d2ab3..0a7aa628e955 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -178,7 +178,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
- if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (POWER_CTRL(ctrl)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n",
__func__);
@@ -186,10 +186,10 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
}
}
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
pslot->hpc_ops->green_led_off(pslot);
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
err("%s: Issue of Set Attention Led command failed\n",
__func__);
@@ -214,14 +214,14 @@ static int board_added(struct slot *p_slot)
__func__, p_slot->device,
ctrl->slot_device_offset, p_slot->hp_slot);
- if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (POWER_CTRL(ctrl)) {
/* Power on slot */
retval = p_slot->hpc_ops->power_on_slot(p_slot);
if (retval)
return retval;
}
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_blink(p_slot);
/* Wait for ~1 second */
@@ -254,7 +254,7 @@ 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))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_on(p_slot);
return 0;
@@ -279,7 +279,7 @@ static int remove_board(struct slot *p_slot)
dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot);
- if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (POWER_CTRL(ctrl)) {
/* power off slot */
retval = p_slot->hpc_ops->power_off_slot(p_slot);
if (retval) {
@@ -289,7 +289,7 @@ static int remove_board(struct slot *p_slot)
}
}
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
@@ -327,7 +327,7 @@ static void pciehp_power_thread(struct work_struct *work)
case POWERON_STATE:
mutex_unlock(&p_slot->lock);
if (pciehp_enable_slot(p_slot) &&
- PWR_LED(p_slot->ctrl->ctrlcap))
+ PWR_LED(p_slot->ctrl))
p_slot->hpc_ops->green_led_off(p_slot);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
@@ -409,9 +409,9 @@ static void handle_button_press_event(struct slot *p_slot)
"press.\n", p_slot->name);
}
/* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_blink(p_slot);
- if (ATTN_LED(ctrl->ctrlcap))
+ if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
schedule_delayed_work(&p_slot->work, 5*HZ);
@@ -427,13 +427,13 @@ static void handle_button_press_event(struct slot *p_slot)
dbg("%s: button cancel\n", __func__);
cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE) {
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_on(p_slot);
} else {
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_off(p_slot);
}
- if (ATTN_LED(ctrl->ctrlcap))
+ if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
info("PCI slot #%s - action canceled due to button press\n",
p_slot->name);
@@ -492,16 +492,16 @@ static void interrupt_event_handler(struct work_struct *work)
handle_button_press_event(p_slot);
break;
case INT_POWER_FAULT:
- if (!POWER_CTRL(ctrl->ctrlcap))
+ if (!POWER_CTRL(ctrl))
break;
- if (ATTN_LED(ctrl->ctrlcap))
+ if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 1);
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
case INT_PRESENCE_OFF:
- if (!HP_SUPR_RM(ctrl->ctrlcap))
+ if (!HP_SUPR_RM(ctrl))
break;
dbg("Surprise Removal\n");
update_slot_info(p_slot);
@@ -531,7 +531,7 @@ int pciehp_enable_slot(struct slot *p_slot)
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%s)\n", __func__,
@@ -541,7 +541,7 @@ int pciehp_enable_slot(struct slot *p_slot)
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%s)\n", __func__,
@@ -576,7 +576,7 @@ int pciehp_disable_slot(struct slot *p_slot)
/* Check to see if (latch closed, card present, power on) */
mutex_lock(&p_slot->ctrl->crit_sect);
- if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
+ if (!HP_SUPR_RM(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%s)\n", __func__,
@@ -586,7 +586,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%s)\n", __func__,
@@ -596,7 +596,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%s)\n", __func__,
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b4bbd07d1e39..891f81a0400c 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -221,6 +221,32 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
add_timer(&ctrl->poll_timer);
}
+static inline int pciehp_request_irq(struct controller *ctrl)
+{
+ int retval, irq = ctrl->pci_dev->irq;
+
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ if (pciehp_poll_mode) {
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
+ return 0;
+ }
+
+ /* Installs the interrupt handler */
+ retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl);
+ if (retval)
+ err("Cannot get irq %d for the hotplug controller\n", irq);
+ return retval;
+}
+
+static inline void pciehp_free_irq(struct controller *ctrl)
+{
+ if (pciehp_poll_mode)
+ del_timer_sync(&ctrl->poll_timer);
+ else
+ free_irq(ctrl->pci_dev->irq, ctrl);
+}
+
static inline int pcie_wait_cmd(struct controller *ctrl)
{
int retval = 0;
@@ -242,17 +268,15 @@ static inline int pcie_wait_cmd(struct controller *ctrl)
/**
* pcie_write_cmd - Issue controller command
- * @slot: slot to which the command is issued
+ * @ctrl: controller to which the command is issued
* @cmd: command value written to slot control register
* @mask: bitmask of slot control register to be modified
*/
-static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
+static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
{
- struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
u16 slot_ctrl;
- unsigned long flags;
mutex_lock(&ctrl->ctrl_lock);
@@ -270,24 +294,24 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
__func__);
}
- spin_lock_irqsave(&ctrl->lock, flags);
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
err("%s: Cannot read SLOTCTRL register\n", __func__);
- goto out_spin_unlock;
+ goto out;
}
slot_ctrl &= ~mask;
- slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE);
+ slot_ctrl |= (cmd & mask);
+ /* Don't enable command completed if caller is changing it. */
+ if (!(mask & CMD_CMPL_INTR_ENABLE))
+ slot_ctrl |= CMD_CMPL_INTR_ENABLE;
ctrl->cmd_busy = 1;
+ smp_mb();
retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
if (retval)
err("%s: Cannot write to SLOTCTRL register\n", __func__);
- out_spin_unlock:
- spin_unlock_irqrestore(&ctrl->lock, flags);
-
/*
* Wait for command completion.
*/
@@ -467,12 +491,7 @@ static int hpc_toggle_emi(struct slot *slot)
slot_cmd = EMI_CTRL;
cmd_mask = EMI_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
return rc;
@@ -499,12 +518,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
default:
return -1;
}
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -519,13 +533,7 @@ static void hpc_set_green_led_on(struct slot *slot)
slot_cmd = 0x0100;
cmd_mask = PWR_LED_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- pcie_write_cmd(slot, slot_cmd, cmd_mask);
-
+ pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
@@ -538,12 +546,7 @@ static void hpc_set_green_led_off(struct slot *slot)
slot_cmd = 0x0300;
cmd_mask = PWR_LED_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
@@ -556,23 +559,19 @@ static void hpc_set_green_led_blink(struct slot *slot)
slot_cmd = 0x0200;
cmd_mask = PWR_LED_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- pcie_write_cmd(slot, slot_cmd, cmd_mask);
-
+ pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
static void hpc_release_ctlr(struct controller *ctrl)
{
- if (pciehp_poll_mode)
- del_timer(&ctrl->poll_timer);
- else
- free_irq(ctrl->pci_dev->irq, ctrl);
+ /* Mask Hot-plug Interrupt Enable */
+ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE))
+ err("%s: Cannot mask hotplut interrupt enable\n", __func__);
+
+ /* Free interrupt handler or interrupt polling timer */
+ pciehp_free_irq(ctrl);
/*
* If this is the last controller to be released, destroy the
@@ -612,19 +611,13 @@ static int hpc_power_on_slot(struct slot * slot)
cmd_mask = PWR_CTRL;
/* Enable detection that we turned off at slot power-off time */
if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd |
- PWR_FAULT_DETECT_ENABLE |
- MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE |
- HP_INTR_ENABLE;
- cmd_mask = cmd_mask |
- PWR_FAULT_DETECT_ENABLE |
- MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE |
- HP_INTR_ENABLE;
+ slot_cmd |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
+ cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
}
- retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
err("%s: Write %x command failed!\n", __func__, slot_cmd);
@@ -697,18 +690,13 @@ static int hpc_power_off_slot(struct slot * slot)
* till the slot is powered on again.
*/
if (!pciehp_poll_mode) {
- slot_cmd = (slot_cmd &
- ~PWR_FAULT_DETECT_ENABLE &
- ~MRL_DETECT_ENABLE &
- ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
- cmd_mask = cmd_mask |
- PWR_FAULT_DETECT_ENABLE |
- MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE |
- HP_INTR_ENABLE;
+ slot_cmd &= ~(PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
+ cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
}
- retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
err("%s: Write command failed!\n", __func__);
retval = -1;
@@ -733,139 +721,56 @@ static int hpc_power_off_slot(struct slot * slot)
static irqreturn_t pcie_isr(int irq, void *dev_id)
{
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;
- unsigned long flags;
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- return IRQ_NONE;
- }
-
- intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
- MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
-
- intr_loc = slot_status & intr_detect;
-
- /* Check to see if it was our interrupt */
- if ( !intr_loc )
- return IRQ_NONE;
+ u16 detected, intr_loc;
- dbg("%s: intr_loc %x\n", __func__, intr_loc);
- /* Mask Hot-plug Interrupt Enable */
- if (!pciehp_poll_mode) {
- spin_lock_irqsave(&ctrl->lock, flags);
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOT_CTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
+ /*
+ * In order to guarantee that all interrupt events are
+ * serviced, we need to re-inspect Slot Status register after
+ * clearing what is presumed to be the last pending interrupt.
+ */
+ intr_loc = 0;
+ do {
+ if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) {
+ err("%s: Cannot read SLOTSTATUS\n", __func__);
return IRQ_NONE;
}
- dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
- __func__, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE &
- ~CMD_CMPL_INTR_ENABLE) | 0x00;
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
+ detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+ MRL_SENS_CHANGED | PRSN_DETECT_CHANGED |
+ CMD_COMPLETED);
+ intr_loc |= detected;
+ if (!intr_loc)
return IRQ_NONE;
- }
- spin_unlock_irqrestore(&ctrl->lock, flags);
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOT_STATUS register\n",
- __func__);
+ if (pciehp_writew(ctrl, SLOTSTATUS, detected)) {
+ err("%s: Cannot write to SLOTSTATUS\n", __func__);
return IRQ_NONE;
}
- dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
- __func__, slot_status);
+ } while (detected);
- /* Clear command complete interrupt caused by this write */
- temp_word = 0x1f;
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n",
- __func__);
- return IRQ_NONE;
- }
- }
+ dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
+ /* Check Command Complete Interrupt Pending */
if (intr_loc & CMD_COMPLETED) {
- /*
- * Command Complete Interrupt Pending
- */
ctrl->cmd_busy = 0;
+ smp_mb();
wake_up_interruptible(&ctrl->queue);
}
+ /* Check MRL Sensor Changed */
if (intr_loc & MRL_SENS_CHANGED)
- pciehp_handle_switch_change(hp_slot, ctrl);
+ pciehp_handle_switch_change(0, ctrl);
+ /* Check Attention Button Pressed */
if (intr_loc & ATTN_BUTTN_PRESSED)
- pciehp_handle_attention_button(hp_slot, ctrl);
+ pciehp_handle_attention_button(0, ctrl);
+ /* Check Presence Detect Changed */
if (intr_loc & PRSN_DETECT_CHANGED)
- pciehp_handle_presence_change(hp_slot, ctrl);
+ pciehp_handle_presence_change(0, ctrl);
+ /* Check Power Fault Detected */
if (intr_loc & PWR_FAULT_DETECTED)
- pciehp_handle_power_fault(hp_slot, ctrl);
-
- /* Clear all events after serving them */
- temp_word = 0x1F;
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __func__);
- return IRQ_NONE;
- }
- /* Unmask Hot-plug Interrupt Enable */
- if (!pciehp_poll_mode) {
- spin_lock_irqsave(&ctrl->lock, flags);
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- return IRQ_NONE;
- }
-
- dbg("%s: Unmask Hot-plug Interrupt Enable\n", __func__);
- temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
-
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- return IRQ_NONE;
- }
- spin_unlock_irqrestore(&ctrl->lock, flags);
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOT_STATUS register\n",
- __func__);
- return IRQ_NONE;
- }
-
- /* Clear command complete interrupt caused by this write */
- temp_word = 0x1F;
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS failed\n",
- __func__);
- return IRQ_NONE;
- }
- dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
- __func__, temp_word);
- }
+ pciehp_handle_power_fault(0, ctrl);
return IRQ_HANDLED;
}
@@ -1052,7 +957,7 @@ static struct hpc_ops pciehp_hpc_ops = {
};
#ifdef CONFIG_ACPI
-int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
+static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
{
acpi_status status;
acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
@@ -1112,7 +1017,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
break;
}
- err("Cannot get control of hotplug hardware for pci %s\n",
+ dbg("Cannot get control of hotplug hardware for pci %s\n",
pci_name(dev));
kfree(string.pointer);
@@ -1123,45 +1028,9 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
static int pcie_init_hardware_part1(struct controller *ctrl,
struct pcie_device *dev)
{
- int rc;
- u16 temp_word;
- u32 slot_cap;
- u16 slot_status;
-
- rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
- if (rc) {
- err("%s: Cannot read SLOTCAP register\n", __func__);
- return -1;
- }
-
/* Mask Hot-plug Interrupt Enable */
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
- return -1;
- }
-
- dbg("%s: SLOTCTRL %x value read %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
- 0x00;
-
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n", __func__);
- return -1;
- }
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- return -1;
- }
-
- temp_word = 0x1F; /* Clear all events */
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __func__);
+ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
+ err("%s: Cannot mask hotplug interrupt enable\n", __func__);
return -1;
}
return 0;
@@ -1169,205 +1038,125 @@ static int pcie_init_hardware_part1(struct controller *ctrl,
int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
{
- int rc;
- u16 temp_word;
- u16 intr_enable = 0;
- u32 slot_cap;
- u16 slot_status;
+ u16 cmd, mask;
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
- goto abort;
- }
-
- intr_enable = intr_enable | PRSN_DETECT_ENABLE;
-
- rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
- if (rc) {
- err("%s: Cannot read SLOTCAP register\n", __func__);
- goto abort;
+ /*
+ * We need to clear all events before enabling hotplug interrupt
+ * notification mechanism in order for hotplug controler to
+ * generate interrupts.
+ */
+ if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+ return -1;
}
- if (ATTN_BUTTN(slot_cap))
- intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
- if (POWER_CTRL(slot_cap))
- intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
- if (MRL_SENS(slot_cap))
- intr_enable = intr_enable | MRL_DETECT_ENABLE;
+ cmd = PRSN_DETECT_ENABLE;
+ if (ATTN_BUTTN(ctrl))
+ cmd |= ATTN_BUTTN_ENABLE;
+ if (POWER_CTRL(ctrl))
+ cmd |= PWR_FAULT_DETECT_ENABLE;
+ if (MRL_SENS(ctrl))
+ cmd |= MRL_DETECT_ENABLE;
+ if (!pciehp_poll_mode)
+ cmd |= HP_INTR_ENABLE;
- temp_word = (temp_word & ~intr_enable) | intr_enable;
+ mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE |
+ PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE;
- if (pciehp_poll_mode) {
- temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
- } else {
- temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- }
-
- /*
- * Unmask Hot-plug Interrupt Enable for the interrupt
- * notification mechanism case.
- */
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n", __func__);
+ if (pcie_write_cmd(ctrl, cmd, mask)) {
+ err("%s: Cannot enable software notification\n", __func__);
goto abort;
}
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- goto abort_disable_intr;
- }
-
- temp_word = 0x1F; /* Clear all events */
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __func__);
- goto abort_disable_intr;
- }
- if (pciehp_force) {
+ if (pciehp_force)
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(ctrl->pci_dev));
- } else {
- rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
- if (rc)
- goto abort_disable_intr;
- }
+ else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev))
+ goto abort_disable_intr;
return 0;
/* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (!rc) {
- temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- }
- if (rc)
+ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE))
err("%s : disabling interrupts failed\n", __func__);
abort:
return -1;
}
-int pcie_init(struct controller *ctrl, struct pcie_device *dev)
+static inline void dbg_ctrl(struct controller *ctrl)
{
- int rc;
- u16 cap_reg;
- u32 slot_cap;
- int cap_base;
- u16 slot_status, slot_ctrl;
- struct pci_dev *pdev;
-
- pdev = dev->port;
- ctrl->pci_dev = pdev; /* save pci_dev in context */
-
- dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
- __func__, pdev->vendor, pdev->device);
+ int i;
+ u16 reg16;
+ struct pci_dev *pdev = ctrl->pci_dev;
- cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (cap_base == 0) {
- dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __func__);
- goto abort;
- }
+ if (!pciehp_debug)
+ return;
- ctrl->cap_base = cap_base;
+ dbg("Hotplug Controller:\n");
+ dbg(" Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", pci_name(pdev), pdev->irq);
+ dbg(" Vendor ID : 0x%04x\n", pdev->vendor);
+ dbg(" Device ID : 0x%04x\n", pdev->device);
+ dbg(" Subsystem ID : 0x%04x\n", pdev->subsystem_device);
+ dbg(" Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor);
+ dbg(" PCIe Cap offset : 0x%02x\n", ctrl->cap_base);
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (!pci_resource_len(pdev, i))
+ continue;
+ dbg(" PCI resource [%d] : 0x%llx@0x%llx\n", i,
+ (unsigned long long)pci_resource_len(pdev, i),
+ (unsigned long long)pci_resource_start(pdev, i));
+ }
+ dbg("Slot Capabilities : 0x%08x\n", ctrl->slot_cap);
+ dbg(" Physical Slot Number : %d\n", ctrl->first_slot);
+ dbg(" Attention Button : %3s\n", ATTN_BUTTN(ctrl) ? "yes" : "no");
+ dbg(" Power Controller : %3s\n", POWER_CTRL(ctrl) ? "yes" : "no");
+ dbg(" MRL Sensor : %3s\n", MRL_SENS(ctrl) ? "yes" : "no");
+ dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no");
+ dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
+ dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
+ dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
+ pciehp_readw(ctrl, SLOTSTATUS, &reg16);
+ dbg("Slot Status : 0x%04x\n", reg16);
+ pciehp_readw(ctrl, SLOTSTATUS, &reg16);
+ dbg("Slot Control : 0x%04x\n", reg16);
+}
- dbg("%s: pcie_cap_base %x\n", __func__, cap_base);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev)
+{
+ u32 slot_cap;
+ struct pci_dev *pdev = dev->port;
- rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
- if (rc) {
- err("%s: Cannot read CAPREG register\n", __func__);
- goto abort;
- }
- dbg("%s: CAPREG offset %x cap_reg %x\n",
- __func__, ctrl->cap_base + CAPREG, cap_reg);
-
- if (((cap_reg & SLOT_IMPL) == 0) ||
- (((cap_reg & DEV_PORT_TYPE) != 0x0040)
- && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
- dbg("%s : This is not a root port or the port is not "
- "connected to a slot\n", __func__);
+ ctrl->pci_dev = pdev;
+ ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (!ctrl->cap_base) {
+ err("%s: Cannot find PCI Express capability\n", __func__);
goto abort;
}
-
- rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
- if (rc) {
+ if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) {
err("%s: Cannot read SLOTCAP register\n", __func__);
goto abort;
}
- dbg("%s: SLOTCAP offset %x slot_cap %x\n",
- __func__, ctrl->cap_base + SLOTCAP, slot_cap);
-
- if (!(slot_cap & HP_CAP)) {
- dbg("%s : This slot is not hot-plug capable\n", __func__);
- goto abort;
- }
- /* For debugging purpose */
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- goto abort;
- }
- dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
- __func__, ctrl->cap_base + SLOTSTATUS, slot_status);
-
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
- goto abort;
- }
- dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
-
- for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
- if (pci_resource_len(pdev, rc) > 0)
- dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
- (unsigned long long)pci_resource_start(pdev, rc),
- (unsigned long long)pci_resource_len(pdev, rc));
-
- 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);
+ ctrl->slot_cap = slot_cap;
+ ctrl->first_slot = slot_cap >> 19;
+ ctrl->slot_device_offset = 0;
+ ctrl->num_slots = 1;
+ ctrl->hpc_ops = &pciehp_hpc_ops;
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
- spin_lock_init(&ctrl->lock);
-
- /* setup wait queue */
init_waitqueue_head(&ctrl->queue);
+ dbg_ctrl(ctrl);
- /* return PCI Controller Info */
- ctrl->slot_device_offset = 0;
- ctrl->num_slots = 1;
- ctrl->first_slot = slot_cap >> 19;
- ctrl->ctrlcap = slot_cap & 0x0000007f;
+ 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 = pcie_init_hardware_part1(ctrl, dev);
- if (rc)
+ if (pcie_init_hardware_part1(ctrl, dev))
goto abort;
- 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(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
- MY_NAME, (void *)ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n",
- __func__, ctrl->pci_dev->irq,
- atomic_read(&pciehp_num_controllers), rc);
- if (rc) {
- err("Can't get irq %d for the hotplug controller\n",
- ctrl->pci_dev->irq);
- goto abort;
- }
- }
- 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);
+ if (pciehp_request_irq(ctrl))
+ goto abort;
/*
* If this is the first controller to be initialized,
@@ -1376,21 +1165,17 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
pciehp_wq = create_singlethread_workqueue("pciehpd");
if (!pciehp_wq) {
- rc = -ENOMEM;
goto abort_free_irq;
}
}
- rc = pcie_init_hardware_part2(ctrl, dev);
- if (rc == 0) {
- ctrl->hpc_ops = &pciehp_hpc_ops;
- return 0;
- }
+ if (pcie_init_hardware_part2(ctrl, dev))
+ goto abort_free_irq;
+
+ return 0;
+
abort_free_irq:
- if (pciehp_poll_mode)
- del_timer_sync(&ctrl->poll_timer);
- else
- free_irq(ctrl->pci_dev->irq, ctrl);
+ pciehp_free_irq(ctrl);
abort:
return -1;
}
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 43816d4b3c43..1648076600fc 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -39,6 +39,7 @@
int shpchp_debug;
int shpchp_poll_mode;
int shpchp_poll_time;
+int shpchp_slot_with_bus;
struct workqueue_struct *shpchp_wq;
#define DRIVER_VERSION "0.4"
@@ -52,9 +53,11 @@ MODULE_LICENSE("GPL");
module_param(shpchp_debug, bool, 0644);
module_param(shpchp_poll_mode, bool, 0644);
module_param(shpchp_poll_time, int, 0644);
+module_param(shpchp_slot_with_bus, bool, 0644);
MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
+MODULE_PARM_DESC(shpchp_slot_with_bus, "Use bus number in the slot name");
#define SHPC_MODULE_NAME "shpchp"
@@ -100,8 +103,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
static void make_slot_name(struct slot *slot)
{
- snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
- slot->bus, slot->number);
+ if (shpchp_slot_with_bus)
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+ else
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d",
+ slot->number);
}
static int init_slots(struct controller *ctrl)
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 1fd8bb765702..66c0fd21894b 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -49,7 +49,7 @@
#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
-#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
+#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
@@ -490,12 +490,12 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
{\
- unsigned long start_time = jiffies;\
+ cycles_t start_time = get_cycles();\
while (1) {\
sts = op (iommu->reg + offset);\
if (cond)\
break;\
- if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT))\
+ if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
panic("DMAR hardware is malfunctioning\n");\
cpu_relax();\
}\
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 26938da8f438..8c61304cbb37 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq)
}
}
-static void msi_set_mask_bit(unsigned int irq, int flag)
+static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
{
struct msi_desc *entry;
@@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits);
- mask_bits &= ~(1);
- mask_bits |= flag;
+ mask_bits &= ~(mask);
+ mask_bits |= flag & mask;
pci_write_config_dword(entry->dev, pos, mask_bits);
} else {
msi_set_enable(entry->dev, !flag);
@@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
void mask_msi_irq(unsigned int irq)
{
- msi_set_mask_bit(irq, 1);
+ msi_set_mask_bits(irq, 1, 1);
msix_flush_writes(irq);
}
void unmask_msi_irq(unsigned int irq)
{
- msi_set_mask_bit(irq, 0);
+ msi_set_mask_bits(irq, 1, 0);
msix_flush_writes(irq);
}
@@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit)
- msi_set_mask_bit(dev->irq, entry->msi_attrib.masked);
+ msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask,
+ entry->msi_attrib.masked);
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
@@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
list_for_each_entry(entry, &dev->msi_list, list) {
write_msi_msg(entry->irq, &entry->msg);
- msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
+ msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked);
}
BUG_ON(list_empty(&dev->msi_list));
@@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev)
pci_write_config_dword(dev,
msi_mask_bits_reg(pos, is_64bit_address(control)),
maskbits);
+ entry->msi_attrib.maskbits_mask = temp;
}
list_add_tail(&entry->list, &dev->msi_list);
@@ -569,10 +571,9 @@ int pci_enable_msi(struct pci_dev* dev)
}
EXPORT_SYMBOL(pci_enable_msi);
-void pci_disable_msi(struct pci_dev* dev)
+void pci_msi_shutdown(struct pci_dev* dev)
{
struct msi_desc *entry;
- int default_irq;
if (!pci_msi_enable || !dev || !dev->msi_enabled)
return;
@@ -583,15 +584,31 @@ void pci_disable_msi(struct pci_dev* dev)
BUG_ON(list_empty(&dev->msi_list));
entry = list_entry(dev->msi_list.next, struct msi_desc, list);
- if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
- return;
+ /* Return the the pci reset with msi irqs unmasked */
+ if (entry->msi_attrib.maskbit) {
+ u32 mask = entry->msi_attrib.maskbits_mask;
+ msi_set_mask_bits(dev->irq, mask, ~mask);
}
-
- default_irq = entry->msi_attrib.default_irq;
- msi_free_irqs(dev);
+ if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
+ return;
/* Restore dev->irq to its default pin-assertion irq */
- dev->irq = default_irq;
+ dev->irq = entry->msi_attrib.default_irq;
+}
+void pci_disable_msi(struct pci_dev* dev)
+{
+ struct msi_desc *entry;
+
+ if (!pci_msi_enable || !dev || !dev->msi_enabled)
+ return;
+
+ pci_msi_shutdown(dev);
+
+ entry = list_entry(dev->msi_list.next, struct msi_desc, list);
+ if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
+ return;
+
+ msi_free_irqs(dev);
}
EXPORT_SYMBOL(pci_disable_msi);
@@ -684,7 +701,7 @@ static void msix_free_all_irqs(struct pci_dev *dev)
msi_free_irqs(dev);
}
-void pci_disable_msix(struct pci_dev* dev)
+void pci_msix_shutdown(struct pci_dev* dev)
{
if (!pci_msi_enable || !dev || !dev->msix_enabled)
return;
@@ -692,6 +709,13 @@ void pci_disable_msix(struct pci_dev* dev)
msix_set_enable(dev, 0);
pci_intx_for_msi(dev, 1);
dev->msix_enabled = 0;
+}
+void pci_disable_msix(struct pci_dev* dev)
+{
+ if (!pci_msi_enable || !dev || !dev->msix_enabled)
+ return;
+
+ pci_msix_shutdown(dev);
msix_free_all_irqs(dev);
}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 72f7476930c8..9d6fc8e6285d 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -19,8 +19,31 @@
#include <linux/pci-acpi.h>
#include "pci.h"
-static u32 ctrlset_buf[3] = {0, 0, 0};
-static u32 global_ctrlsets = 0;
+struct acpi_osc_data {
+ acpi_handle handle;
+ u32 ctrlset_buf[3];
+ u32 global_ctrlsets;
+ struct list_head sibiling;
+};
+static LIST_HEAD(acpi_osc_data_list);
+
+static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle)
+{
+ struct acpi_osc_data *data;
+
+ list_for_each_entry(data, &acpi_osc_data_list, sibiling) {
+ if (data->handle == handle)
+ return data;
+ }
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return NULL;
+ INIT_LIST_HEAD(&data->sibiling);
+ data->handle = handle;
+ list_add_tail(&data->sibiling, &acpi_osc_data_list);
+ return data;
+}
+
static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
static acpi_status
@@ -37,8 +60,27 @@ acpi_query_osc (
union acpi_object *out_obj;
u32 osc_dw0;
acpi_status *ret_status = (acpi_status *)retval;
+ struct acpi_osc_data *osc_data;
+ u32 flags = (unsigned long)context, temp;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_OSC", &tmp);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ osc_data = acpi_get_osc_data(handle);
+ if (!osc_data) {
+ printk(KERN_ERR "acpi osc data array is full\n");
+ return AE_ERROR;
+ }
+
+ osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
+
+ /* do _OSC query for all possible controls */
+ temp = osc_data->ctrlset_buf[OSC_CONTROL_TYPE];
+ osc_data->ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+ osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
-
/* Setting up input parameters */
input.count = 4;
input.pointer = in_params;
@@ -51,13 +93,11 @@ acpi_query_osc (
in_params[2].integer.value = 3;
in_params[3].type = ACPI_TYPE_BUFFER;
in_params[3].buffer.length = 12;
- in_params[3].buffer.pointer = (u8 *)context;
+ in_params[3].buffer.pointer = (u8 *)osc_data->ctrlset_buf;
status = acpi_evaluate_object(handle, "_OSC", &input, &output);
- if (ACPI_FAILURE (status)) {
- *ret_status = status;
- return status;
- }
+ if (ACPI_FAILURE(status))
+ goto out_nofree;
out_obj = output.pointer;
if (out_obj->type != ACPI_TYPE_BUFFER) {
@@ -76,7 +116,8 @@ acpi_query_osc (
printk(KERN_DEBUG "_OSC invalid revision\n");
if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
/* Update Global Control Set */
- global_ctrlsets = *((u32 *)(out_obj->buffer.pointer+8));
+ osc_data->global_ctrlsets =
+ *((u32 *)(out_obj->buffer.pointer + 8));
status = AE_OK;
goto query_osc_out;
}
@@ -85,12 +126,21 @@ acpi_query_osc (
}
/* Update Global Control Set */
- global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
+ osc_data->global_ctrlsets = *((u32 *)(out_obj->buffer.pointer + 8));
status = AE_OK;
query_osc_out:
kfree(output.pointer);
+out_nofree:
*ret_status = status;
+
+ osc_data->ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
+ osc_data->ctrlset_buf[OSC_CONTROL_TYPE] = temp;
+ if (ACPI_FAILURE(status)) {
+ /* no osc support at all */
+ osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] = 0;
+ }
+
return status;
}
@@ -165,28 +215,15 @@ run_osc_out:
**/
acpi_status __pci_osc_support_set(u32 flags, const char *hid)
{
- u32 temp;
- acpi_status retval;
+ acpi_status retval = AE_NOT_FOUND;
if (!(flags & OSC_SUPPORT_MASKS)) {
return AE_TYPE;
}
- ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
-
- /* do _OSC query for all possible controls */
- temp = ctrlset_buf[OSC_CONTROL_TYPE];
- ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
- ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
acpi_get_devices(hid,
acpi_query_osc,
- ctrlset_buf,
+ (void *)(unsigned long)flags,
(void **) &retval );
- ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
- ctrlset_buf[OSC_CONTROL_TYPE] = temp;
- if (ACPI_FAILURE(retval)) {
- /* no osc support at all */
- ctrlset_buf[OSC_SUPPORT_TYPE] = 0;
- }
return AE_OK;
}
@@ -201,19 +238,31 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
{
acpi_status status;
u32 ctrlset;
+ acpi_handle tmp;
+ struct acpi_osc_data *osc_data;
+
+ status = acpi_get_handle(handle, "_OSC", &tmp);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ osc_data = acpi_get_osc_data(handle);
+ if (!osc_data) {
+ printk(KERN_ERR "acpi osc data array is full\n");
+ return AE_ERROR;
+ }
ctrlset = (flags & OSC_CONTROL_MASKS);
if (!ctrlset) {
return AE_TYPE;
}
- if (ctrlset_buf[OSC_SUPPORT_TYPE] &&
- ((global_ctrlsets & ctrlset) != ctrlset)) {
+ if (osc_data->ctrlset_buf[OSC_SUPPORT_TYPE] &&
+ ((osc_data->global_ctrlsets & ctrlset) != ctrlset)) {
return AE_SUPPORT;
}
- ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
- status = acpi_run_osc(handle, ctrlset_buf);
+ osc_data->ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
+ status = acpi_run_osc(handle, osc_data->ctrlset_buf);
if (ACPI_FAILURE (status)) {
- ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
+ osc_data->ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
}
return status;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e8d94fafc280..72cf61ed8f96 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -360,6 +360,8 @@ static void pci_device_shutdown(struct device *dev)
if (drv && drv->shutdown)
drv->shutdown(pci_dev);
+ pci_msi_shutdown(pci_dev);
+ pci_msix_shutdown(pci_dev);
}
/**
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 25b04fb2517d..5a0c6ad53f8e 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -33,7 +33,7 @@ source "drivers/pci/pcie/aer/Kconfig"
config PCIEASPM
bool "PCI Express ASPM support(Experimental)"
depends on PCI && EXPERIMENTAL && PCIEPORTBUS
- default y
+ default n
help
This enables PCI Express ASPM (Active State Power Management) and
Clock Power Management. ASPM supports state L0/L0s/L1.
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f991359f0c36..3706ce7972dd 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -842,6 +842,21 @@ static void set_pcie_port_type(struct pci_dev *pdev)
* reading the dword at 0x100 which must either be 0 or a valid extended
* capability header.
*/
+int pci_cfg_space_size_ext(struct pci_dev *dev)
+{
+ u32 status;
+
+ if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL)
+ goto fail;
+ if (status == 0xffffffff)
+ goto fail;
+
+ return PCI_CFG_SPACE_EXP_SIZE;
+
+ fail:
+ return PCI_CFG_SPACE_SIZE;
+}
+
int pci_cfg_space_size(struct pci_dev *dev)
{
int pos;
@@ -858,12 +873,7 @@ int pci_cfg_space_size(struct pci_dev *dev)
goto fail;
}
- if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL)
- goto fail;
- if (status == 0xffffffff)
- goto fail;
-
- return PCI_CFG_SPACE_EXP_SIZE;
+ return pci_cfg_space_size_ext(dev);
fail:
return PCI_CFG_SPACE_SIZE;
@@ -964,7 +974,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->dev.release = pci_release_dev;
pci_dev_get(dev);
- set_dev_node(&dev->dev, pcibus_to_node(bus));
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
@@ -1080,6 +1089,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
return max;
}
+void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b)
+{
+}
+
struct pci_bus * pci_create_bus(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
@@ -1119,6 +1132,9 @@ struct pci_bus * pci_create_bus(struct device *parent,
goto dev_reg_err;
b->bridge = get_device(dev);
+ if (!parent)
+ set_dev_node(b->bridge, pcibus_to_node(b));
+
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge;
sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
@@ -1136,6 +1152,8 @@ struct pci_bus * pci_create_bus(struct device *parent,
b->resource[0] = &ioport_resource;
b->resource[1] = &iomem_resource;
+ set_pci_bus_resources_arch_default(b);
+
return b;
dev_create_file_err:
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index ef18fcd641e2..963a97642ae9 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -293,6 +293,7 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file)
#endif /* HAVE_PCI_MMAP */
static const struct file_operations proc_bus_pci_operations = {
+ .owner = THIS_MODULE,
.llseek = proc_bus_pci_lseek,
.read = proc_bus_pci_read,
.write = proc_bus_pci_write,
@@ -406,11 +407,10 @@ int pci_proc_attach_device(struct pci_dev *dev)
}
sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir);
+ e = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir,
+ &proc_bus_pci_operations, dev);
if (!e)
return -ENOMEM;
- e->proc_fops = &proc_bus_pci_operations;
- e->data = dev;
e->size = dev->cfg_size;
dev->procent = e;
@@ -462,6 +462,7 @@ static int proc_bus_pci_dev_open(struct inode *inode, struct file *file)
return seq_open(file, &proc_bus_pci_devices_op);
}
static const struct file_operations proc_bus_pci_dev_operations = {
+ .owner = THIS_MODULE,
.open = proc_bus_pci_dev_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -470,12 +471,10 @@ static const struct file_operations proc_bus_pci_dev_operations = {
static int __init pci_proc_init(void)
{
- struct proc_dir_entry *entry;
struct pci_dev *dev = NULL;
- proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
- entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
- if (entry)
- entry->proc_fops = &proc_bus_pci_dev_operations;
+ proc_bus_pci_dir = proc_mkdir("bus/pci", NULL);
+ proc_create("devices", 0, proc_bus_pci_dir,
+ &proc_bus_pci_dev_operations);
proc_initialized = 1;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_proc_attach_device(dev);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index afd914ebe215..dabb563f51d9 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1503,8 +1503,7 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f
(f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
#ifdef DEBUG
dev_dbg(&dev->dev, "calling ");
- print_fn_descriptor_symbol("%s()\n",
- (unsigned long) f->hook);
+ print_fn_descriptor_symbol("%s\n", f->hook);
#endif
f->hook(dev);
}
@@ -1826,6 +1825,7 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
{
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
index 74e051535d6c..c78d77fd7e3b 100644
--- a/drivers/pcmcia/au1000_db1x00.c
+++ b/drivers/pcmcia/au1000_db1x00.c
@@ -194,7 +194,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
default:
pwr |= SET_VCC_VPP(0,0,sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
state->Vcc,
state->Vpp);
break;
@@ -215,7 +215,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
default:
pwr |= SET_VCC_VPP(0,0,sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
state->Vcc,
state->Vpp);
break;
@@ -224,7 +224,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
default: /* what's this ? */
pwr |= SET_VCC_VPP(0,0,sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
break;
}
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index b693367d38cd..75e8f8505e47 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -41,6 +41,7 @@
#include <linux/notifier.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <asm/io.h>
@@ -71,7 +72,7 @@ extern struct au1000_pcmcia_socket au1000_pcmcia_socket[];
u32 *pcmcia_base_vaddrs[2];
extern const unsigned long mips_io_port_base;
-DECLARE_MUTEX(pcmcia_sockets_lock);
+static DEFINE_MUTEX(pcmcia_sockets_lock);
static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = {
au1x_board_init,
@@ -472,7 +473,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
struct skt_dev_info *sinfo = dev_get_drvdata(dev);
int i;
- down(&pcmcia_sockets_lock);
+ mutex_lock(&pcmcia_sockets_lock);
dev_set_drvdata(dev, NULL);
for (i = 0; i < sinfo->nskt; i++) {
@@ -488,7 +489,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
}
kfree(sinfo);
- up(&pcmcia_sockets_lock);
+ mutex_unlock(&pcmcia_sockets_lock);
return 0;
}
@@ -501,13 +502,13 @@ static int au1x00_drv_pcmcia_probe(struct device *dev)
{
int i, ret = -ENODEV;
- down(&pcmcia_sockets_lock);
+ mutex_lock(&pcmcia_sockets_lock);
for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
ret = au1x00_pcmcia_hw_init[i](dev);
if (ret == 0)
break;
}
- up(&pcmcia_sockets_lock);
+ mutex_unlock(&pcmcia_sockets_lock);
return ret;
}
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index 86c0808d6a05..157e41423a0a 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -244,7 +244,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -272,7 +272,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -300,7 +300,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -309,7 +309,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default: /* what's this ? */
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, configure->vcc);
+ __func__, configure->vcc);
break;
}
@@ -353,7 +353,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -374,7 +374,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -383,7 +383,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
default: /* what's this ? */
pcr |= SET_VCC_VPP(0,0);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, configure->vcc);
+ __func__, configure->vcc);
break;
}
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index ce9d5c44a7b5..c78ed5347510 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -56,7 +56,7 @@
#define PCMCIA_IRQ AU1000_GPIO_4
#if 0
-#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args)
+#define DEBUG(x, args...) printk(__func__ ": " x, ##args)
#else
#define DEBUG(x,args...)
#endif
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 714baaeb6da1..fb2f38dc92c5 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -209,7 +209,7 @@ static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
}
}
-int cb_alloc(struct pcmcia_socket * s)
+int __ref cb_alloc(struct pcmcia_socket * s)
{
struct pci_bus *bus = s->cb_dev->subordinate;
struct pci_dev *dev;
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 06a85d7d5aa2..36379535f9da 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -402,15 +402,6 @@ EXPORT_SYMBOL(pcmcia_replace_cis);
======================================================================*/
-static inline u16 cis_get_u16(void *ptr)
-{
- return le16_to_cpu(get_unaligned((__le16 *) ptr));
-}
-static inline u32 cis_get_u32(void *ptr)
-{
- return le32_to_cpu(get_unaligned((__le32 *) ptr));
-}
-
typedef struct tuple_flags {
u_int link_space:4;
u_int has_link:1;
@@ -471,7 +462,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
/* Get indirect link from the MFC tuple */
read_cis_cache(s, LINK_SPACE(tuple->Flags),
tuple->LinkOffset, 5, link);
- ofs = cis_get_u32(link + 1);
+ ofs = get_unaligned_le32(link + 1);
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
/* Move to the next indirect link */
tuple->LinkOffset += 5;
@@ -679,8 +670,8 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
if (tuple->TupleDataLen < 5)
return CS_BAD_TUPLE;
p = (u_char *) tuple->TupleData;
- csum->addr = tuple->CISOffset + cis_get_u16(p) - 2;
- csum->len = cis_get_u16(p + 2);
+ csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
+ csum->len = get_unaligned_le16(p + 2);
csum->sum = *(p + 4);
return CS_SUCCESS;
}
@@ -691,7 +682,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- link->addr = cis_get_u32(tuple->TupleData);
+ link->addr = get_unaligned_le32(tuple->TupleData);
return CS_SUCCESS;
}
@@ -710,7 +701,7 @@ static int parse_longlink_mfc(tuple_t *tuple,
return CS_BAD_TUPLE;
for (i = 0; i < link->nfn; i++) {
link->fn[i].space = *p; p++;
- link->fn[i].addr = cis_get_u32(p);
+ link->fn[i].addr = get_unaligned_le32(p);
p += 4;
}
return CS_SUCCESS;
@@ -800,8 +791,8 @@ static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- m->manf = cis_get_u16(tuple->TupleData);
- m->card = cis_get_u16(tuple->TupleData + 2);
+ m->manf = get_unaligned_le16(tuple->TupleData);
+ m->card = get_unaligned_le16(tuple->TupleData + 2);
return CS_SUCCESS;
}
@@ -1100,7 +1091,7 @@ static int parse_cftable_entry(tuple_t *tuple,
break;
case 0x20:
entry->mem.nwin = 1;
- entry->mem.win[0].len = cis_get_u16(p) << 8;
+ entry->mem.win[0].len = get_unaligned_le16(p) << 8;
entry->mem.win[0].card_addr = 0;
entry->mem.win[0].host_addr = 0;
p += 2;
@@ -1108,8 +1099,8 @@ static int parse_cftable_entry(tuple_t *tuple,
break;
case 0x40:
entry->mem.nwin = 1;
- entry->mem.win[0].len = cis_get_u16(p) << 8;
- entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8;
+ entry->mem.win[0].len = get_unaligned_le16(p) << 8;
+ entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q) return CS_BAD_TUPLE;
@@ -1146,7 +1137,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
p = (u_char *)tuple->TupleData;
bar->attr = *p;
p += 2;
- bar->size = cis_get_u32(p);
+ bar->size = get_unaligned_le32(p);
return CS_SUCCESS;
}
@@ -1159,7 +1150,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
return CS_BAD_TUPLE;
config->last_idx = *(++p);
p++;
- config->base = cis_get_u32(p);
+ config->base = get_unaligned_le32(p);
config->subtuples = tuple->TupleDataLen - 6;
return CS_SUCCESS;
}
@@ -1275,7 +1266,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
v2->vers = p[0];
v2->comply = p[1];
- v2->dindex = cis_get_u16(p +2 );
+ v2->dindex = get_unaligned_le16(p +2 );
v2->vspec8 = p[6];
v2->vspec9 = p[7];
v2->nhdr = p[8];
@@ -1316,8 +1307,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
fmt->type = p[0];
fmt->edc = p[1];
- fmt->offset = cis_get_u32(p + 2);
- fmt->length = cis_get_u32(p + 6);
+ fmt->offset = get_unaligned_le32(p + 2);
+ fmt->length = get_unaligned_le32(p + 6);
return CS_SUCCESS;
}
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 56230dbd347a..29276bd28295 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -652,6 +652,9 @@ static int pccardd(void *__skt)
complete(&skt->thread_done);
return 0;
}
+ ret = pccard_sysfs_add_socket(&skt->dev);
+ if (ret)
+ dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
add_wait_queue(&skt->thread_wait, &wait);
complete(&skt->thread_done);
@@ -694,6 +697,7 @@ static int pccardd(void *__skt)
remove_wait_queue(&skt->thread_wait, &wait);
/* remove from the device core */
+ pccard_sysfs_remove_socket(&skt->dev);
device_unregister(&skt->dev);
return 0;
@@ -940,20 +944,13 @@ EXPORT_SYMBOL(pcmcia_socket_class);
static int __init init_pcmcia_cs(void)
{
- int ret;
-
init_completion(&pcmcia_unload);
- ret = class_register(&pcmcia_socket_class);
- if (ret)
- return (ret);
- return class_interface_register(&pccard_sysfs_interface);
+ return class_register(&pcmcia_socket_class);
}
static void __exit exit_pcmcia_cs(void)
{
- class_interface_unregister(&pccard_sysfs_interface);
class_unregister(&pcmcia_socket_class);
-
wait_for_completion(&pcmcia_unload);
}
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 9fa207e3c7b3..e7d5d141f24d 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -121,7 +121,8 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
void release_resource_db(struct pcmcia_socket *s);
/* In socket_sysfs.c */
-extern struct class_interface pccard_sysfs_interface;
+extern int pccard_sysfs_add_socket(struct device *dev);
+extern void pccard_sysfs_remove_socket(struct device *dev);
/* In cs.c */
extern struct rw_semaphore pcmcia_socket_list_rwsem;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5a85871f5ee9..e40775443d04 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1520,7 +1520,7 @@ static void pcmcia_bus_remove_socket(struct device *dev,
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
-static struct class_interface pcmcia_bus_interface = {
+static struct class_interface pcmcia_bus_interface __refdata = {
.class = &pcmcia_socket_class,
.add_dev = &pcmcia_bus_add_socket,
.remove_dev = &pcmcia_bus_remove_socket,
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index e54ecc580d9e..e13618656ff7 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -53,7 +53,7 @@ static int i82092aa_socket_resume (struct pci_dev *dev)
}
#endif
-static struct pci_driver i82092aa_pci_drv = {
+static struct pci_driver i82092aa_pci_driver = {
.name = "i82092aa",
.id_table = i82092aa_pci_ids,
.probe = i82092aa_pci_probe,
@@ -714,13 +714,13 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
static int i82092aa_module_init(void)
{
- return pci_register_driver(&i82092aa_pci_drv);
+ return pci_register_driver(&i82092aa_pci_driver);
}
static void i82092aa_module_exit(void)
{
enter("i82092aa_module_exit");
- pci_unregister_driver(&i82092aa_pci_drv);
+ pci_unregister_driver(&i82092aa_pci_driver);
if (sockets[0].io_base>0)
release_region(sockets[0].io_base, 2);
leave("i82092aa_module_exit");
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index bb6db3a582b2..46314b420765 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -153,7 +153,7 @@ omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
static int omap_cf_ss_suspend(struct pcmcia_socket *s)
{
- pr_debug("%s: %s\n", driver_name, __FUNCTION__);
+ pr_debug("%s: %s\n", driver_name, __func__);
return omap_cf_set_socket(s, &dead_socket);
}
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 27523c5f4dad..5f186abca108 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -787,7 +787,7 @@ void __init pcmcia_setup_ioctl(void) {
major_dev = i;
#ifdef CONFIG_PROC_FS
- proc_pccard = proc_mkdir("pccard", proc_bus);
+ proc_pccard = proc_mkdir("bus/pccard", NULL);
if (proc_pccard)
create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
#endif
@@ -798,7 +798,7 @@ void __exit pcmcia_cleanup_ioctl(void) {
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
remove_proc_entry("drivers", proc_pccard);
- remove_proc_entry("pccard", proc_bus);
+ remove_proc_entry("bus/pccard", NULL);
}
#endif
if (major_dev != -1)
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index abc10fe49bd8..8bed1dab9039 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -778,7 +778,7 @@ static struct pci_device_id pd6729_pci_ids[] = {
};
MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
-static struct pci_driver pd6729_pci_drv = {
+static struct pci_driver pd6729_pci_driver = {
.name = "pd6729",
.id_table = pd6729_pci_ids,
.probe = pd6729_pci_probe,
@@ -791,12 +791,12 @@ static struct pci_driver pd6729_pci_drv = {
static int pd6729_module_init(void)
{
- return pci_register_driver(&pd6729_pci_drv);
+ return pci_register_driver(&pd6729_pci_driver);
}
static void pd6729_module_exit(void)
{
- pci_unregister_driver(&pd6729_pci_drv);
+ pci_unregister_driver(&pd6729_pci_driver);
}
module_init(pd6729_module_init);
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
index 4a05802213c8..881ec8a8e389 100644
--- a/drivers/pcmcia/pxa2xx_lubbock.c
+++ b/drivers/pcmcia/pxa2xx_lubbock.c
@@ -87,7 +87,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
}
@@ -104,7 +104,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
pa_dwr_set |= GPIO_A0;
else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
break;
}
@@ -128,14 +128,14 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
break;
}
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
break;
}
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 6fa5eaaab8af..145b85e0f02c 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -99,7 +99,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
default:
printk(KERN_ERR "%s(): bad Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
}
@@ -111,7 +111,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
power |= MST_PCMCIA_PWR_VPP_VCC;
} else {
printk(KERN_ERR "%s(): bad Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
}
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index a8d100707721..0fcf763b9175 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -1045,7 +1045,7 @@ static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
device_remove_file(dev, *attr);
}
-static struct class_interface pccard_rsrc_interface = {
+static struct class_interface pccard_rsrc_interface __refdata = {
.class = &pcmcia_socket_class,
.add_dev = &pccard_sysfs_add_rsrc,
.remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
index 7c57fdd3c8d7..ce133ce81c10 100644
--- a/drivers/pcmcia/sa1100_assabet.c
+++ b/drivers/pcmcia/sa1100_assabet.c
@@ -66,14 +66,14 @@ assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_stat
case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
- __FUNCTION__);
+ __func__);
case 33: /* Can only apply 3.3V to the CF slot. */
mask = ASSABET_BCR_CF_PWR;
break;
default:
- printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __func__,
state->Vcc);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
index 62bfc7566ec2..607c3f326eca 100644
--- a/drivers/pcmcia/sa1100_badge4.c
+++ b/drivers/pcmcia/sa1100_badge4.c
@@ -82,14 +82,14 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state
case 0:
if ((state->Vcc != 0) &&
(state->Vcc != badge4_pcmvcc)) {
- complain_about_jumpering(__FUNCTION__, "pcmvcc",
+ complain_about_jumpering(__func__, "pcmvcc",
badge4_pcmvcc, state->Vcc);
// Apply power regardless of the jumpering.
// return -1;
}
if ((state->Vpp != 0) &&
(state->Vpp != badge4_pcmvpp)) {
- complain_about_jumpering(__FUNCTION__, "pcmvpp",
+ complain_about_jumpering(__func__, "pcmvpp",
badge4_pcmvpp, state->Vpp);
return -1;
}
@@ -98,7 +98,7 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state
case 1:
if ((state->Vcc != 0) &&
(state->Vcc != badge4_cfvcc)) {
- complain_about_jumpering(__FUNCTION__, "cfvcc",
+ complain_about_jumpering(__func__, "cfvcc",
badge4_cfvcc, state->Vcc);
return -1;
}
@@ -143,7 +143,7 @@ int pcmcia_badge4_init(struct device *dev)
if (machine_is_badge4()) {
printk(KERN_INFO
"%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
- __FUNCTION__,
+ __func__,
badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2);
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index 549a1529fe35..7c3951a2675d 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -63,7 +63,7 @@ cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
index 6284c35dabc6..2167e6714d2d 100644
--- a/drivers/pcmcia/sa1100_jornada720.c
+++ b/drivers/pcmcia/sa1100_jornada720.c
@@ -42,7 +42,7 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
-printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
+printk("%s(): config socket %d vcc %d vpp %d\n", __func__,
skt->nr, state->Vcc, state->Vpp);
switch (skt->nr) {
@@ -74,7 +74,7 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
index 5bc9e9532b9d..687492fcd5b4 100644
--- a/drivers/pcmcia/sa1100_neponset.c
+++ b/drivers/pcmcia/sa1100_neponset.c
@@ -59,7 +59,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
ncr_set = NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
break;
@@ -71,7 +71,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
break;
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
index 9456f5478d09..494912fccc0d 100644
--- a/drivers/pcmcia/sa1100_shannon.c
+++ b/drivers/pcmcia/sa1100_shannon.c
@@ -73,19 +73,19 @@ shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
{
switch (state->Vcc) {
case 0: /* power off */
- printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __func__);
break;
case 50:
- printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __func__);
case 33:
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
return -1;
}
- printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __func__);
/* Silently ignore Vpp, output enable, speaker enable. */
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index 04d6f7f75f78..42567de894b9 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -90,7 +90,7 @@ simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
local_irq_restore(flags);
return -1;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index aa7779d89752..420a77540f41 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
+#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
@@ -353,7 +354,7 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m
(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
if (map->map >= MAX_IO_WIN) {
- printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+ printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
map->map);
return -1;
}
@@ -578,7 +579,7 @@ EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
LIST_HEAD(soc_pcmcia_sockets);
-DECLARE_MUTEX(soc_pcmcia_sockets_lock);
+static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
static const char *skt_names[] = {
"PCMCIA socket 0",
@@ -601,11 +602,11 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
struct cpufreq_freqs *freqs = data;
int ret = 0;
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
list_for_each_entry(skt, &soc_pcmcia_sockets, node)
if ( skt->ops->frequency_change )
ret += skt->ops->frequency_change(skt, val, freqs);
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
return ret;
}
@@ -642,7 +643,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
struct soc_pcmcia_socket *skt;
int ret, i;
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
if (!sinfo) {
@@ -782,7 +783,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
kfree(sinfo);
out:
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
return ret;
}
@@ -793,7 +794,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev)
dev_set_drvdata(dev, NULL);
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
for (i = 0; i < sinfo->nskt; i++) {
struct soc_pcmcia_socket *skt = &sinfo->skt[i];
@@ -818,7 +819,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev)
if (list_empty(&soc_pcmcia_sockets))
soc_pcmcia_cpufreq_unregister();
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
kfree(sinfo);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 6f14126889b3..1edc1da9d353 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -133,7 +133,6 @@ extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_
extern struct list_head soc_pcmcia_sockets;
-extern struct semaphore soc_pcmcia_sockets_lock;
extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr);
extern int soc_common_drv_pcmcia_remove(struct device *dev);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index b4409002b7f8..562384d6f321 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -356,19 +356,23 @@ static ssize_t pccard_store_cis(struct kobject *kobj,
}
-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,
+static struct attribute *pccard_socket_attributes[] = {
+ &dev_attr_card_type.attr,
+ &dev_attr_card_voltage.attr,
+ &dev_attr_card_vpp.attr,
+ &dev_attr_card_vcc.attr,
+ &dev_attr_card_insert.attr,
+ &dev_attr_card_pm_state.attr,
+ &dev_attr_card_eject.attr,
+ &dev_attr_card_irq_mask.attr,
+ &dev_attr_available_resources_setup_done.attr,
NULL,
};
+static const struct attribute_group socket_attrs = {
+ .attrs = pccard_socket_attributes,
+};
+
static struct bin_attribute pccard_cis_attr = {
.attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
.size = 0x200,
@@ -376,35 +380,21 @@ static struct bin_attribute pccard_cis_attr = {
.write = pccard_store_cis,
};
-static int __devinit pccard_sysfs_add_socket(struct device *dev,
- struct class_interface *class_intf)
+int pccard_sysfs_add_socket(struct device *dev)
{
- struct device_attribute **attr;
int ret = 0;
- for (attr = pccard_socket_attributes; *attr; attr++) {
- ret = device_create_file(dev, *attr);
+ ret = sysfs_create_group(&dev->kobj, &socket_attrs);
+ if (!ret) {
+ ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
if (ret)
- break;
+ sysfs_remove_group(&dev->kobj, &socket_attrs);
}
- if (!ret)
- ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
-
return ret;
}
-static void __devexit pccard_sysfs_remove_socket(struct device *dev,
- struct class_interface *class_intf)
+void pccard_sysfs_remove_socket(struct device *dev)
{
- struct device_attribute **attr;
-
sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
- for (attr = pccard_socket_attributes; *attr; attr++)
- device_remove_file(dev, *attr);
+ sysfs_remove_group(&dev->kobj, &socket_attrs);
}
-
-struct class_interface pccard_sysfs_interface = {
- .class = &pcmcia_socket_class,
- .add_dev = &pccard_sysfs_add_socket,
- .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
-};
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 31a633f65547..886dac823ed6 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -1,12 +1,79 @@
extern spinlock_t pnp_lock;
void *pnp_alloc(long size);
+
+int pnp_register_protocol(struct pnp_protocol *protocol);
+void pnp_unregister_protocol(struct pnp_protocol *protocol);
+
+#define PNP_EISA_ID_MASK 0x7fffffff
+void pnp_eisa_id_to_string(u32 id, char *str);
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid);
+struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid);
+
+int pnp_add_device(struct pnp_dev *dev);
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id);
int pnp_interface_attach_device(struct pnp_dev *dev);
+
+int pnp_add_card(struct pnp_card *card);
+struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id);
+void pnp_remove_card(struct pnp_card *card);
+int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
+void pnp_remove_card_device(struct pnp_dev *dev);
+
+struct pnp_option *pnp_build_option(int priority);
+struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
+struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
+ int priority);
+int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_irq *data);
+int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_dma *data);
+int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_port *data);
+int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_mem *data);
+void pnp_init_resources(struct pnp_dev *dev);
+
void pnp_fixup_device(struct pnp_dev *dev);
void pnp_free_option(struct pnp_option *option);
int __pnp_add_device(struct pnp_dev *dev);
void __pnp_remove_device(struct pnp_dev *dev);
-int pnp_check_port(struct pnp_dev * dev, int idx);
-int pnp_check_mem(struct pnp_dev * dev, int idx);
-int pnp_check_irq(struct pnp_dev * dev, int idx);
-int pnp_check_dma(struct pnp_dev * dev, int idx);
+int pnp_check_port(struct pnp_dev *dev, struct resource *res);
+int pnp_check_mem(struct pnp_dev *dev, struct resource *res);
+int pnp_check_irq(struct pnp_dev *dev, struct resource *res);
+int pnp_check_dma(struct pnp_dev *dev, struct resource *res);
+
+void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc);
+
+void pnp_init_resource(struct resource *res);
+
+struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev,
+ unsigned int type, unsigned int num);
+
+#define PNP_MAX_PORT 40
+#define PNP_MAX_MEM 24
+#define PNP_MAX_IRQ 2
+#define PNP_MAX_DMA 2
+
+struct pnp_resource {
+ struct resource res;
+ unsigned int index; /* ISAPNP config register index */
+};
+
+struct pnp_resource_table {
+ struct pnp_resource port[PNP_MAX_PORT];
+ struct pnp_resource mem[PNP_MAX_MEM];
+ struct pnp_resource dma[PNP_MAX_DMA];
+ struct pnp_resource irq[PNP_MAX_IRQ];
+};
+
+struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
+ int flags);
+struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
+ int flags);
+struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags);
+struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index da1c9909eb44..a762a4176736 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
+#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/pnp.h>
#include "base.h"
@@ -100,19 +101,33 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
* @id: pointer to a pnp_id structure
* @card: pointer to the desired card
*/
-int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card)
+struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id)
{
- struct pnp_id *ptr;
+ struct pnp_id *dev_id, *ptr;
- id->next = NULL;
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ if (!dev_id)
+ return NULL;
+
+ dev_id->id[0] = id[0];
+ dev_id->id[1] = id[1];
+ dev_id->id[2] = id[2];
+ dev_id->id[3] = tolower(id[3]);
+ dev_id->id[4] = tolower(id[4]);
+ dev_id->id[5] = tolower(id[5]);
+ dev_id->id[6] = tolower(id[6]);
+ dev_id->id[7] = '\0';
+
+ dev_id->next = NULL;
ptr = card->id;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
- ptr->next = id;
+ ptr->next = dev_id;
else
- card->id = id;
- return 0;
+ card->id = dev_id;
+
+ return dev_id;
}
static void pnp_free_card_ids(struct pnp_card *card)
@@ -136,6 +151,31 @@ static void pnp_release_card(struct device *dmdev)
kfree(card);
}
+struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnpid)
+{
+ struct pnp_card *card;
+ struct pnp_id *dev_id;
+
+ card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL);
+ if (!card)
+ return NULL;
+
+ card->protocol = protocol;
+ card->number = id;
+
+ card->dev.parent = &card->protocol->dev;
+ sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number,
+ card->number);
+
+ dev_id = pnp_add_card_id(card, pnpid);
+ if (!dev_id) {
+ kfree(card);
+ return NULL;
+ }
+
+ return card;
+}
+
static ssize_t pnp_show_card_name(struct device *dmdev,
struct device_attribute *attr, char *buf)
{
@@ -191,9 +231,6 @@ int pnp_add_card(struct pnp_card *card)
int error;
struct list_head *pos, *temp;
- sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number,
- card->number);
- card->dev.parent = &card->protocol->dev;
card->dev.bus = NULL;
card->dev.release = &pnp_release_card;
error = device_register(&card->dev);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 7d366ca672d3..20771b7d4482 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -106,18 +106,53 @@ static void pnp_release_device(struct device *dmdev)
pnp_free_option(dev->independent);
pnp_free_option(dev->dependent);
pnp_free_ids(dev);
+ kfree(dev->res);
kfree(dev);
}
-int __pnp_add_device(struct pnp_dev *dev)
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid)
{
- int ret;
+ struct pnp_dev *dev;
+ struct pnp_id *dev_id;
- pnp_fixup_device(dev);
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->res = kzalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+ if (!dev->res) {
+ kfree(dev);
+ return NULL;
+ }
+
+ dev->protocol = protocol;
+ dev->number = id;
+ dev->dma_mask = DMA_24BIT_MASK;
+
+ dev->dev.parent = &dev->protocol->dev;
dev->dev.bus = &pnp_bus_type;
dev->dev.dma_mask = &dev->dma_mask;
- dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK;
+ dev->dev.coherent_dma_mask = dev->dma_mask;
dev->dev.release = &pnp_release_device;
+
+ sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
+ dev->number);
+
+ dev_id = pnp_add_id(dev, pnpid);
+ if (!dev_id) {
+ kfree(dev->res);
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+int __pnp_add_device(struct pnp_dev *dev)
+{
+ int ret;
+
+ pnp_fixup_device(dev);
dev->status = PNP_READY;
spin_lock(&pnp_lock);
list_add_tail(&dev->global_list, &pnp_global);
@@ -145,9 +180,6 @@ int pnp_add_device(struct pnp_dev *dev)
if (dev->card)
return -EINVAL;
- dev->dev.parent = &dev->protocol->dev;
- sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
- dev->number);
ret = __pnp_add_device(dev);
if (ret)
return ret;
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e85cbf116db1..d3f869ee1d92 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -226,22 +226,36 @@ void pnp_unregister_driver(struct pnp_driver *drv)
/**
* pnp_add_id - adds an EISA id to the specified device
- * @id: pointer to a pnp_id structure
* @dev: pointer to the desired device
+ * @id: pointer to an EISA id string
*/
-int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id)
{
- struct pnp_id *ptr;
+ struct pnp_id *dev_id, *ptr;
- id->next = NULL;
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ if (!dev_id)
+ return NULL;
+
+ dev_id->id[0] = id[0];
+ dev_id->id[1] = id[1];
+ dev_id->id[2] = id[2];
+ dev_id->id[3] = tolower(id[3]);
+ dev_id->id[4] = tolower(id[4]);
+ dev_id->id[5] = tolower(id[5]);
+ dev_id->id[6] = tolower(id[6]);
+ dev_id->id[7] = '\0';
+
+ dev_id->next = NULL;
ptr = dev->id;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
- ptr->next = id;
+ ptr->next = dev_id;
else
- dev->id = id;
- return 0;
+ dev->id = dev_id;
+
+ return dev_id;
}
EXPORT_SYMBOL(pnp_register_driver);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 982658477a58..5695a79f3a52 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -248,6 +248,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
+ struct resource *res;
int i, ret;
pnp_info_buffer_t *buffer;
@@ -267,50 +268,46 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
else
pnp_printf(buffer, "disabled\n");
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (pnp_port_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "io");
- if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " 0x%llx-0x%llx\n",
- (unsigned long long)
- pnp_port_start(dev, i),
- (unsigned long long)pnp_port_end(dev,
- i));
+ (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (pnp_mem_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "mem");
- if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " 0x%llx-0x%llx\n",
- (unsigned long long)
- pnp_mem_start(dev, i),
- (unsigned long long)pnp_mem_end(dev,
- i));
+ (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
}
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (pnp_irq_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "irq");
- if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " %lld\n",
- (unsigned long long)pnp_irq(dev, i));
+ (unsigned long long) res->start);
}
}
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (pnp_dma_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "dma");
- if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " %lld\n",
- (unsigned long long)pnp_dma(dev, i));
+ (unsigned long long) res->start);
}
}
ret = (buffer->curr - buf);
@@ -323,8 +320,10 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
const char *ubuf, size_t count)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
+ struct pnp_resource *pnp_res;
char *buf = (void *)ubuf;
int retval = 0;
+ resource_size_t start, end;
if (dev->status & PNP_ATTACHED) {
retval = -EBUSY;
@@ -351,20 +350,20 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
if (!strnicmp(buf, "auto", 4)) {
if (dev->active)
goto done;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
retval = pnp_auto_config_dev(dev);
goto done;
}
if (!strnicmp(buf, "clear", 5)) {
if (dev->active)
goto done;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
goto done;
}
if (!strnicmp(buf, "get", 3)) {
mutex_lock(&pnp_res_mutex);
if (pnp_can_read(dev))
- dev->protocol->get(dev, &dev->res);
+ dev->protocol->get(dev);
mutex_unlock(&pnp_res_mutex);
goto done;
}
@@ -373,7 +372,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
if (dev->active)
goto done;
buf += 3;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
mutex_lock(&pnp_res_mutex);
while (1) {
while (isspace(*buf))
@@ -382,76 +381,60 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
buf += 2;
while (isspace(*buf))
++buf;
- dev->res.port_resource[nport].start =
- simple_strtoul(buf, &buf, 0);
+ start = simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
++buf;
if (*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
- dev->res.port_resource[nport].end =
- simple_strtoul(buf, &buf, 0);
+ end = simple_strtoul(buf, &buf, 0);
} else
- dev->res.port_resource[nport].end =
- dev->res.port_resource[nport].start;
- dev->res.port_resource[nport].flags =
- IORESOURCE_IO;
- nport++;
- if (nport >= PNP_MAX_PORT)
- break;
+ end = start;
+ pnp_res = pnp_add_io_resource(dev, start, end,
+ 0);
+ if (pnp_res)
+ pnp_res->index = nport++;
continue;
}
if (!strnicmp(buf, "mem", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.mem_resource[nmem].start =
- simple_strtoul(buf, &buf, 0);
+ start = simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
++buf;
if (*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
- dev->res.mem_resource[nmem].end =
- simple_strtoul(buf, &buf, 0);
+ end = simple_strtoul(buf, &buf, 0);
} else
- dev->res.mem_resource[nmem].end =
- dev->res.mem_resource[nmem].start;
- dev->res.mem_resource[nmem].flags =
- IORESOURCE_MEM;
- nmem++;
- if (nmem >= PNP_MAX_MEM)
- break;
+ end = start;
+ pnp_res = pnp_add_mem_resource(dev, start, end,
+ 0);
+ if (pnp_res)
+ pnp_res->index = nmem++;
continue;
}
if (!strnicmp(buf, "irq", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.irq_resource[nirq].start =
- dev->res.irq_resource[nirq].end =
- simple_strtoul(buf, &buf, 0);
- dev->res.irq_resource[nirq].flags =
- IORESOURCE_IRQ;
- nirq++;
- if (nirq >= PNP_MAX_IRQ)
- break;
+ start = simple_strtoul(buf, &buf, 0);
+ pnp_res = pnp_add_irq_resource(dev, start, 0);
+ if (pnp_res)
+ pnp_res->index = nirq++;
continue;
}
if (!strnicmp(buf, "dma", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.dma_resource[ndma].start =
- dev->res.dma_resource[ndma].end =
- simple_strtoul(buf, &buf, 0);
- dev->res.dma_resource[ndma].flags =
- IORESOURCE_DMA;
- ndma++;
- if (ndma >= PNP_MAX_DMA)
- break;
+ start = simple_strtoul(buf, &buf, 0);
+ pnp_res = pnp_add_dma_resource(dev, start, 0);
+ if (pnp_res)
+ pnp_res->index = ndma++;
continue;
}
break;
diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile
index cac18bbfb817..3e38f06f8d78 100644
--- a/drivers/pnp/isapnp/Makefile
+++ b/drivers/pnp/isapnp/Makefile
@@ -5,3 +5,7 @@
isapnp-proc-$(CONFIG_PROC_FS) = proc.o
obj-y := core.o compat.o $(isapnp-proc-y)
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 257f5d827d83..f1bccdbdeb08 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -44,6 +44,8 @@
#include <linux/mutex.h>
#include <asm/io.h>
+#include "../base.h"
+
#if 0
#define ISAPNP_REGION_OK
#endif
@@ -88,6 +90,14 @@ MODULE_LICENSE("GPL");
#define _LTAG_MEM32RANGE 0x85
#define _LTAG_FIXEDMEM32RANGE 0x86
+/* Logical device control and configuration registers */
+
+#define ISAPNP_CFG_ACTIVATE 0x30 /* byte */
+#define ISAPNP_CFG_MEM 0x40 /* 4 * dword */
+#define ISAPNP_CFG_PORT 0x60 /* 8 * word */
+#define ISAPNP_CFG_IRQ 0x70 /* 2 * word */
+#define ISAPNP_CFG_DMA 0x74 /* 2 * byte */
+
/*
* Sizes of ISAPNP logical device configuration register sets.
* See PNP-ISA-v1.0a.pdf, Appendix A.
@@ -388,28 +398,6 @@ static void __init isapnp_skip_bytes(int count)
}
/*
- * Parse EISA id.
- */
-static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor,
- unsigned short device)
-{
- struct pnp_id *id;
-
- if (!dev)
- return;
- id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!id)
- return;
- sprintf(id->id, "%c%c%c%x%x%x%x",
- 'A' + ((vendor >> 2) & 0x3f) - 1,
- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
- 'A' + ((vendor >> 8) & 0x1f) - 1,
- (device >> 4) & 0x0f,
- device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
- pnp_add_id(id, dev);
-}
-
-/*
* Parse logical device tag.
*/
static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
@@ -417,30 +405,31 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
{
unsigned char tmp[6];
struct pnp_dev *dev;
+ u32 eisa_id;
+ char id[8];
isapnp_peek(tmp, size);
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ eisa_id = tmp[0] | tmp[1] << 8 | tmp[2] << 16 | tmp[3] << 24;
+ pnp_eisa_id_to_string(eisa_id, id);
+
+ dev = pnp_alloc_dev(&isapnp_protocol, number, id);
if (!dev)
return NULL;
- dev->number = number;
- isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);
- dev->regs = tmp[4];
+
dev->card = card;
- if (size > 5)
- dev->regs |= tmp[5] << 8;
- dev->protocol = &isapnp_protocol;
dev->capabilities |= PNP_CONFIGURABLE;
dev->capabilities |= PNP_READ;
dev->capabilities |= PNP_WRITE;
dev->capabilities |= PNP_DISABLE;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
return dev;
}
/*
* Add IRQ resource to resources list.
*/
-static void __init isapnp_parse_irq_resource(struct pnp_option *option,
+static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[3];
@@ -457,13 +446,14 @@ static void __init isapnp_parse_irq_resource(struct pnp_option *option,
irq->flags = tmp[2];
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
/*
* Add DMA resource to resources list.
*/
-static void __init isapnp_parse_dma_resource(struct pnp_option *option,
+static void __init isapnp_parse_dma_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[2];
@@ -475,13 +465,14 @@ static void __init isapnp_parse_dma_resource(struct pnp_option *option,
return;
dma->map = tmp[0];
dma->flags = tmp[1];
- pnp_register_dma_resource(option, dma);
+ pnp_register_dma_resource(dev, option, dma);
}
/*
* Add port resource to resources list.
*/
-static void __init isapnp_parse_port_resource(struct pnp_option *option,
+static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[7];
@@ -496,13 +487,14 @@ static void __init isapnp_parse_port_resource(struct pnp_option *option,
port->align = tmp[5];
port->size = tmp[6];
port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
/*
* Add fixed port resource to resources list.
*/
-static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
+static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[3];
@@ -516,13 +508,14 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
port->size = tmp[2];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
/*
* Add memory resource to resources list.
*/
-static void __init isapnp_parse_mem_resource(struct pnp_option *option,
+static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[9];
@@ -537,13 +530,14 @@ static void __init isapnp_parse_mem_resource(struct pnp_option *option,
mem->align = (tmp[6] << 8) | tmp[5];
mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
mem->flags = tmp[0];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
/*
* Add 32-bit memory resource to resources list.
*/
-static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
+static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[17];
@@ -560,13 +554,14 @@ static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
mem->size =
(tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
mem->flags = tmp[0];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
/*
* Add 32-bit fixed memory resource to resources list.
*/
-static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
+static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[9];
@@ -581,7 +576,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
mem->align = 0;
mem->flags = tmp[0];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
/*
@@ -613,6 +608,8 @@ static int __init isapnp_create_device(struct pnp_card *card,
unsigned char type, tmp[17];
struct pnp_option *option;
struct pnp_dev *dev;
+ u32 eisa_id;
+ char id[8];
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
@@ -652,8 +649,10 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _STAG_COMPATDEVID:
if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {
isapnp_peek(tmp, 4);
- isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0],
- (tmp[3] << 8) | tmp[2]);
+ eisa_id = tmp[0] | tmp[1] << 8 |
+ tmp[2] << 16 | tmp[3] << 24;
+ pnp_eisa_id_to_string(eisa_id, id);
+ pnp_add_id(dev, id);
compat++;
size = 0;
}
@@ -661,13 +660,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _STAG_IRQ:
if (size < 2 || size > 3)
goto __skip;
- isapnp_parse_irq_resource(option, size);
+ isapnp_parse_irq_resource(dev, option, size);
size = 0;
break;
case _STAG_DMA:
if (size != 2)
goto __skip;
- isapnp_parse_dma_resource(option, size);
+ isapnp_parse_dma_resource(dev, option, size);
size = 0;
break;
case _STAG_STARTDEP:
@@ -687,17 +686,18 @@ static int __init isapnp_create_device(struct pnp_card *card,
if (size != 0)
goto __skip;
priority = 0;
+ dev_dbg(&dev->dev, "end dependent options\n");
break;
case _STAG_IOPORT:
if (size != 7)
goto __skip;
- isapnp_parse_port_resource(option, size);
+ isapnp_parse_port_resource(dev, option, size);
size = 0;
break;
case _STAG_FIXEDIO:
if (size != 3)
goto __skip;
- isapnp_parse_fixed_port_resource(option, size);
+ isapnp_parse_fixed_port_resource(dev, option, size);
size = 0;
break;
case _STAG_VENDOR:
@@ -705,7 +705,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEMRANGE:
if (size != 9)
goto __skip;
- isapnp_parse_mem_resource(option, size);
+ isapnp_parse_mem_resource(dev, option, size);
size = 0;
break;
case _LTAG_ANSISTR:
@@ -720,13 +720,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEM32RANGE:
if (size != 17)
goto __skip;
- isapnp_parse_mem32_resource(option, size);
+ isapnp_parse_mem32_resource(dev, option, size);
size = 0;
break;
case _LTAG_FIXEDMEM32RANGE:
if (size != 9)
goto __skip;
- isapnp_parse_fixed_mem32_resource(option, size);
+ isapnp_parse_fixed_mem32_resource(dev, option, size);
size = 0;
break;
case _STAG_END:
@@ -734,9 +734,8 @@ static int __init isapnp_create_device(struct pnp_card *card,
isapnp_skip_bytes(size);
return 1;
default:
- printk(KERN_ERR
- "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n",
- type, dev->number, card->number);
+ dev_err(&dev->dev, "unknown tag %#x (card %i), "
+ "ignored\n", type, card->number);
}
__skip:
if (size > 0)
@@ -789,9 +788,8 @@ static void __init isapnp_parse_resource_map(struct pnp_card *card)
isapnp_skip_bytes(size);
return;
default:
- printk(KERN_ERR
- "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n",
- type, card->number);
+ dev_err(&card->dev, "unknown tag %#x, ignored\n",
+ type);
}
__skip:
if (size > 0)
@@ -822,25 +820,6 @@ static unsigned char __init isapnp_checksum(unsigned char *data)
}
/*
- * Parse EISA id for ISA PnP card.
- */
-static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor,
- unsigned short device)
-{
- struct pnp_id *id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
-
- if (!id)
- return;
- sprintf(id->id, "%c%c%c%x%x%x%x",
- 'A' + ((vendor >> 2) & 0x3f) - 1,
- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
- 'A' + ((vendor >> 8) & 0x1f) - 1,
- (device >> 4) & 0x0f,
- device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
- pnp_add_card_id(id, card);
-}
-
-/*
* Build device list for all present ISA PnP devices.
*/
static int __init isapnp_build_device_list(void)
@@ -848,6 +827,8 @@ static int __init isapnp_build_device_list(void)
int csn;
unsigned char header[9], checksum;
struct pnp_card *card;
+ u32 eisa_id;
+ char id[8];
isapnp_wait();
isapnp_key();
@@ -855,32 +836,30 @@ static int __init isapnp_build_device_list(void)
isapnp_wake(csn);
isapnp_peek(header, 9);
checksum = isapnp_checksum(header);
+ eisa_id = header[0] | header[1] << 8 |
+ header[2] << 16 | header[3] << 24;
+ pnp_eisa_id_to_string(eisa_id, id);
+ card = pnp_alloc_card(&isapnp_protocol, csn, id);
+ if (!card)
+ continue;
+
#if 0
- printk(KERN_DEBUG
+ dev_info(&card->dev,
"vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
header[0], header[1], header[2], header[3], header[4],
header[5], header[6], header[7], header[8]);
- printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
+ dev_info(&card->dev, "checksum = %#x\n", checksum);
#endif
- if ((card =
- kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
- continue;
-
- card->number = csn;
INIT_LIST_HEAD(&card->devices);
- isapnp_parse_card_id(card, (header[1] << 8) | header[0],
- (header[3] << 8) | header[2]);
card->serial =
(header[7] << 24) | (header[6] << 16) | (header[5] << 8) |
header[4];
isapnp_checksum_value = 0x00;
isapnp_parse_resource_map(card);
if (isapnp_checksum_value != 0x00)
- printk(KERN_ERR
- "isapnp: checksum for device %i is not valid (0x%x)\n",
- csn, isapnp_checksum_value);
+ dev_err(&card->dev, "invalid checksum %#x\n",
+ isapnp_checksum_value);
card->checksum = isapnp_checksum_value;
- card->protocol = &isapnp_protocol;
pnp_add_card(card);
}
@@ -947,100 +926,117 @@ EXPORT_SYMBOL(isapnp_cfg_begin);
EXPORT_SYMBOL(isapnp_cfg_end);
EXPORT_SYMBOL(isapnp_write_byte);
-static int isapnp_read_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int isapnp_get_resources(struct pnp_dev *dev)
{
- int tmp, ret;
+ struct pnp_resource *pnp_res;
+ int i, ret;
+ dev_dbg(&dev->dev, "get resources\n");
+ pnp_init_resources(dev);
+ isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
- if (dev->active) {
- for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
- ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
- if (!ret)
- continue;
- res->port_resource[tmp].start = ret;
- res->port_resource[tmp].flags = IORESOURCE_IO;
+ if (!dev->active)
+ goto __end;
+
+ for (i = 0; i < ISAPNP_MAX_PORT; i++) {
+ ret = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
+ if (ret) {
+ pnp_res = pnp_add_io_resource(dev, ret, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
}
- for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
- ret =
- isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
- if (!ret)
- continue;
- res->mem_resource[tmp].start = ret;
- res->mem_resource[tmp].flags = IORESOURCE_MEM;
+ }
+ for (i = 0; i < ISAPNP_MAX_MEM; i++) {
+ ret = isapnp_read_word(ISAPNP_CFG_MEM + (i << 3)) << 8;
+ if (ret) {
+ pnp_res = pnp_add_mem_resource(dev, ret, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
}
- for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) {
- ret =
- (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
- 8);
- if (!ret)
- continue;
- res->irq_resource[tmp].start =
- res->irq_resource[tmp].end = ret;
- res->irq_resource[tmp].flags = IORESOURCE_IRQ;
+ }
+ for (i = 0; i < ISAPNP_MAX_IRQ; i++) {
+ ret = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)) >> 8;
+ if (ret) {
+ pnp_res = pnp_add_irq_resource(dev, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
}
- for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
- ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
- if (ret == 4)
- continue;
- res->dma_resource[tmp].start =
- res->dma_resource[tmp].end = ret;
- res->dma_resource[tmp].flags = IORESOURCE_DMA;
+ }
+ for (i = 0; i < ISAPNP_MAX_DMA; i++) {
+ ret = isapnp_read_byte(ISAPNP_CFG_DMA + i);
+ if (ret != 4) {
+ pnp_res = pnp_add_dma_resource(dev, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
}
}
- return 0;
-}
-
-static int isapnp_get_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
-{
- int ret;
- pnp_init_resource_table(res);
- isapnp_cfg_begin(dev->card->number, dev->number);
- ret = isapnp_read_resources(dev, res);
+__end:
isapnp_cfg_end();
- return ret;
+ return 0;
}
-static int isapnp_set_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int isapnp_set_resources(struct pnp_dev *dev)
{
- int tmp;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ int tmp, index;
+ dev_dbg(&dev->dev, "set resources\n");
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
- for (tmp = 0;
- tmp < ISAPNP_MAX_PORT
- && (res->port_resource[tmp].
- flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
- tmp++)
- isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
- res->port_resource[tmp].start);
- for (tmp = 0;
- tmp < ISAPNP_MAX_IRQ
- && (res->irq_resource[tmp].
- flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
- tmp++) {
- int irq = res->irq_resource[tmp].start;
- if (irq == 2)
- irq = 9;
- isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
+ for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set io %d to %#llx\n",
+ index, (unsigned long long) res->start);
+ isapnp_write_word(ISAPNP_CFG_PORT + (index << 1),
+ res->start);
+ }
+ }
+ for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ int irq = res->start;
+ if (irq == 2)
+ irq = 9;
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set irq %d to %d\n", index, irq);
+ isapnp_write_byte(ISAPNP_CFG_IRQ + (index << 1), irq);
+ }
+ }
+ for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set dma %d to %lld\n",
+ index, (unsigned long long) res->start);
+ isapnp_write_byte(ISAPNP_CFG_DMA + index, res->start);
+ }
+ }
+ for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set mem %d to %#llx\n",
+ index, (unsigned long long) res->start);
+ isapnp_write_word(ISAPNP_CFG_MEM + (index << 3),
+ (res->start >> 8) & 0xffff);
+ }
}
- for (tmp = 0;
- tmp < ISAPNP_MAX_DMA
- && (res->dma_resource[tmp].
- flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
- tmp++)
- isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
- res->dma_resource[tmp].start);
- for (tmp = 0;
- tmp < ISAPNP_MAX_MEM
- && (res->mem_resource[tmp].
- flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
- tmp++)
- isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
- (res->mem_resource[tmp].start >> 8) & 0xffff);
/* FIXME: We aren't handling 32bit mems properly here */
isapnp_activate(dev->number);
isapnp_cfg_end();
@@ -1138,13 +1134,13 @@ static int __init isapnp_init(void)
protocol_for_each_card(&isapnp_protocol, card) {
cards++;
if (isapnp_verbose) {
- printk(KERN_INFO "isapnp: Card '%s'\n",
- card->name[0] ? card->name : "Unknown");
+ dev_info(&card->dev, "card '%s'\n",
+ card->name[0] ? card->name : "unknown");
if (isapnp_verbose < 2)
continue;
card_for_each_dev(card, dev) {
- printk(KERN_INFO "isapnp: Device '%s'\n",
- dev->name[0] ? dev->name : "Unknown");
+ dev_info(&card->dev, "device '%s'\n",
+ dev->name[0] ? dev->name : "unknown");
}
}
}
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 2b8266c3d40f..3f94edab25fa 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -85,6 +85,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,
}
static const struct file_operations isapnp_proc_bus_file_operations = {
+ .owner = THIS_MODULE,
.llseek = isapnp_proc_bus_lseek,
.read = isapnp_proc_bus_read,
};
@@ -102,12 +103,10 @@ static int isapnp_proc_attach_device(struct pnp_dev *dev)
return -ENOMEM;
}
sprintf(name, "%02x", dev->number);
- e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
+ e = dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, de,
+ &isapnp_proc_bus_file_operations, dev);
if (!e)
return -ENOMEM;
- e->proc_fops = &isapnp_proc_bus_file_operations;
- e->owner = THIS_MODULE;
- e->data = dev;
e->size = 256;
return 0;
}
@@ -116,7 +115,7 @@ int __init isapnp_proc_init(void)
{
struct pnp_dev *dev;
- isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
+ isapnp_proc_bus_dir = proc_mkdir("bus/isapnp", NULL);
protocol_for_each_dev(&isapnp_protocol, dev) {
isapnp_proc_attach_device(dev);
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index c28caf272c11..bea0914ff947 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -19,100 +19,118 @@ DEFINE_MUTEX(pnp_res_mutex);
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
- if (idx >= PNP_MAX_PORT) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many I/O port resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
+ res = &pnp_res->res;
+
/* check if this resource has been manually set, if so skip */
- if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx "
+ "flags %#lx\n", idx, (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
return 1;
-
- start = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
- flags = &dev->res.port_resource[idx].flags;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IO;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_IO;
+ res->flags &= ~IORESOURCE_UNSET;
if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " io %d disabled\n", idx);
return 1; /* skip disabled resource requests */
}
- *start = rule->min;
- *end = *start + rule->size - 1;
+ res->start = rule->min;
+ res->end = res->start + rule->size - 1;
/* run through until pnp_check_port is happy */
- while (!pnp_check_port(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
+ while (!pnp_check_port(dev, res)) {
+ res->start += rule->align;
+ res->end = res->start + rule->size - 1;
+ if (res->start > rule->max || !rule->align) {
+ dev_dbg(&dev->dev, " couldn't assign io %d\n", idx);
return 0;
+ }
}
+ dev_dbg(&dev->dev, " assign io %d %#llx-%#llx\n", idx,
+ (unsigned long long) res->start, (unsigned long long) res->end);
return 1;
}
static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
- if (idx >= PNP_MAX_MEM) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many memory resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
+ res = &pnp_res->res;
+
/* check if this resource has been manually set, if so skip */
- if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx "
+ "flags %#lx\n", idx, (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
return 1;
-
- start = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
- flags = &dev->res.mem_resource[idx].flags;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_MEM;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_MEM;
+ res->flags &= ~IORESOURCE_UNSET;
/* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
- *flags |= IORESOURCE_READONLY;
+ res->flags |= IORESOURCE_READONLY;
if (rule->flags & IORESOURCE_MEM_CACHEABLE)
- *flags |= IORESOURCE_CACHEABLE;
+ res->flags |= IORESOURCE_CACHEABLE;
if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
- *flags |= IORESOURCE_RANGELENGTH;
+ res->flags |= IORESOURCE_RANGELENGTH;
if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
- *flags |= IORESOURCE_SHADOWABLE;
+ res->flags |= IORESOURCE_SHADOWABLE;
if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " mem %d disabled\n", idx);
return 1; /* skip disabled resource requests */
}
- *start = rule->min;
- *end = *start + rule->size - 1;
+ res->start = rule->min;
+ res->end = res->start + rule->size - 1;
/* run through until pnp_check_mem is happy */
- while (!pnp_check_mem(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
+ while (!pnp_check_mem(dev, res)) {
+ res->start += rule->align;
+ res->end = res->start + rule->size - 1;
+ if (res->start > rule->max || !rule->align) {
+ dev_dbg(&dev->dev, " couldn't assign mem %d\n", idx);
return 0;
+ }
}
+ dev_dbg(&dev->dev, " assign mem %d %#llx-%#llx\n", idx,
+ (unsigned long long) res->start, (unsigned long long) res->end);
return 1;
}
static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
int i;
/* IRQ priority: this table is good for i386 */
@@ -120,49 +138,59 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};
- if (idx >= PNP_MAX_IRQ) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many IRQ resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
+ res = &pnp_res->res;
+
/* check if this resource has been manually set, if so skip */
- if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n",
+ idx, (int) res->start, res->flags);
return 1;
-
- start = &dev->res.irq_resource[idx].start;
- end = &dev->res.irq_resource[idx].end;
- flags = &dev->res.irq_resource[idx].flags;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IRQ;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_IRQ;
+ res->flags &= ~IORESOURCE_UNSET;
if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
- *flags |= IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " irq %d disabled\n", idx);
return 1; /* skip disabled resource requests */
}
/* TBD: need check for >16 IRQ */
- *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
- if (*start < PNP_IRQ_NR) {
- *end = *start;
+ res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+ if (res->start < PNP_IRQ_NR) {
+ res->end = res->start;
+ dev_dbg(&dev->dev, " assign irq %d %d\n", idx,
+ (int) res->start);
return 1;
}
for (i = 0; i < 16; i++) {
if (test_bit(xtab[i], rule->map)) {
- *start = *end = xtab[i];
- if (pnp_check_irq(dev, idx))
+ res->start = res->end = xtab[i];
+ if (pnp_check_irq(dev, res)) {
+ dev_dbg(&dev->dev, " assign irq %d %d\n", idx,
+ (int) res->start);
return 1;
+ }
}
}
+ dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
return 0;
}
static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
int i;
/* DMA priority: this table is good for i386 */
@@ -170,71 +198,89 @@ static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1, 3, 5, 6, 7, 0, 2, 4
};
- if (idx >= PNP_MAX_DMA) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many DMA resources\n");
return;
}
+ res = &pnp_res->res;
+
/* check if this resource has been manually set, if so skip */
- if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n",
+ idx, (int) res->start, res->flags);
return;
-
- start = &dev->res.dma_resource[idx].start;
- end = &dev->res.dma_resource[idx].end;
- flags = &dev->res.dma_resource[idx].flags;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_DMA;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_DMA;
+ res->flags &= ~IORESOURCE_UNSET;
for (i = 0; i < 8; i++) {
if (rule->map & (1 << xtab[i])) {
- *start = *end = xtab[i];
- if (pnp_check_dma(dev, idx))
+ res->start = res->end = xtab[i];
+ if (pnp_check_dma(dev, res)) {
+ dev_dbg(&dev->dev, " assign dma %d %d\n", idx,
+ (int) res->start);
return;
+ }
}
}
#ifdef MAX_DMA_CHANNELS
- *start = *end = MAX_DMA_CHANNELS;
+ res->start = res->end = MAX_DMA_CHANNELS;
#endif
- *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " disable dma %d\n", idx);
+}
+
+void pnp_init_resource(struct resource *res)
+{
+ unsigned long type;
+
+ type = res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_IRQ | IORESOURCE_DMA);
+
+ res->name = NULL;
+ res->flags = type | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ if (type == IORESOURCE_IRQ || type == IORESOURCE_DMA) {
+ res->start = -1;
+ res->end = -1;
+ } else {
+ res->start = 0;
+ res->end = 0;
+ }
}
/**
* pnp_init_resources - Resets a resource table to default values.
* @table: pointer to the desired resource table
*/
-void pnp_init_resource_table(struct pnp_resource_table *table)
+void pnp_init_resources(struct pnp_dev *dev)
{
+ struct resource *res;
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
- table->irq_resource[idx].name = NULL;
- table->irq_resource[idx].start = -1;
- table->irq_resource[idx].end = -1;
- table->irq_resource[idx].flags =
- IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->irq[idx].res;
+ res->flags = IORESOURCE_IRQ;
+ pnp_init_resource(res);
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
- table->dma_resource[idx].name = NULL;
- table->dma_resource[idx].start = -1;
- table->dma_resource[idx].end = -1;
- table->dma_resource[idx].flags =
- IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->dma[idx].res;
+ res->flags = IORESOURCE_DMA;
+ pnp_init_resource(res);
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
- table->port_resource[idx].name = NULL;
- table->port_resource[idx].start = 0;
- table->port_resource[idx].end = 0;
- table->port_resource[idx].flags =
- IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->port[idx].res;
+ res->flags = IORESOURCE_IO;
+ pnp_init_resource(res);
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
- table->mem_resource[idx].name = NULL;
- table->mem_resource[idx].start = 0;
- table->mem_resource[idx].end = 0;
- table->mem_resource[idx].flags =
- IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->mem[idx].res;
+ res->flags = IORESOURCE_MEM;
+ pnp_init_resource(res);
}
}
@@ -242,41 +288,38 @@ void pnp_init_resource_table(struct pnp_resource_table *table)
* pnp_clean_resources - clears resources that were not manually set
* @res: the resources to clean
*/
-static void pnp_clean_resource_table(struct pnp_resource_table *res)
+static void pnp_clean_resource_table(struct pnp_dev *dev)
{
+ struct resource *res;
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
- if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->irq_resource[idx].start = -1;
- res->irq_resource[idx].end = -1;
- res->irq_resource[idx].flags =
- IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->irq[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_IRQ;
+ pnp_init_resource(res);
+ }
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
- if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->dma_resource[idx].start = -1;
- res->dma_resource[idx].end = -1;
- res->dma_resource[idx].flags =
- IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->dma[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_DMA;
+ pnp_init_resource(res);
+ }
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
- if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->port_resource[idx].start = 0;
- res->port_resource[idx].end = 0;
- res->port_resource[idx].flags =
- IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->port[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_IO;
+ pnp_init_resource(res);
+ }
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
- if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->mem_resource[idx].start = 0;
- res->mem_resource[idx].end = 0;
- res->mem_resource[idx].flags =
- IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->mem[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_MEM;
+ pnp_init_resource(res);
+ }
}
}
@@ -298,9 +341,11 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
if (!pnp_can_configure(dev))
return -ENODEV;
+ dbg_pnp_show_resources(dev, "before pnp_assign_resources");
mutex_lock(&pnp_res_mutex);
- pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
+ pnp_clean_resource_table(dev);
if (dev->independent) {
+ dev_dbg(&dev->dev, "assigning independent options\n");
port = dev->independent->port;
mem = dev->independent->mem;
irq = dev->independent->irq;
@@ -333,6 +378,8 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
if (depnum) {
struct pnp_option *dep;
int i;
+
+ dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
for (i = 1, dep = dev->dependent; i < depnum;
i++, dep = dep->next)
if (!dep)
@@ -368,68 +415,17 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
goto fail;
mutex_unlock(&pnp_res_mutex);
+ dbg_pnp_show_resources(dev, "after pnp_assign_resources");
return 1;
fail:
- pnp_clean_resource_table(&dev->res);
+ pnp_clean_resource_table(dev);
mutex_unlock(&pnp_res_mutex);
+ dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
return 0;
}
/**
- * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
- * @dev: pointer to the desired device
- * @res: pointer to the new resource config
- * @mode: 0 or PNP_CONFIG_FORCE
- *
- * This function can be used by drivers that want to manually set thier resources.
- */
-int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
- int mode)
-{
- int i;
- struct pnp_resource_table *bak;
-
- if (!pnp_can_configure(dev))
- return -ENODEV;
- bak = pnp_alloc(sizeof(struct pnp_resource_table));
- if (!bak)
- return -ENOMEM;
- *bak = dev->res;
-
- mutex_lock(&pnp_res_mutex);
- dev->res = *res;
- if (!(mode & PNP_CONFIG_FORCE)) {
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_check_port(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_check_mem(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (!pnp_check_irq(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (!pnp_check_dma(dev, i))
- goto fail;
- }
- }
- mutex_unlock(&pnp_res_mutex);
-
- kfree(bak);
- return 0;
-
-fail:
- dev->res = *bak;
- mutex_unlock(&pnp_res_mutex);
- kfree(bak);
- return -EINVAL;
-}
-
-/**
* pnp_auto_config_dev - automatically assigns resources to a device
* @dev: pointer to the desired device
*/
@@ -473,7 +469,8 @@ int pnp_start_dev(struct pnp_dev *dev)
return -EINVAL;
}
- if (dev->protocol->set(dev, &dev->res) < 0) {
+ dbg_pnp_show_resources(dev, "pnp_start_dev");
+ if (dev->protocol->set(dev) < 0) {
dev_err(&dev->dev, "activation failed\n");
return -EIO;
}
@@ -549,30 +546,13 @@ int pnp_disable_dev(struct pnp_dev *dev)
/* release the resources so that other devices can use them */
mutex_lock(&pnp_res_mutex);
- pnp_clean_resource_table(&dev->res);
+ pnp_clean_resource_table(dev);
mutex_unlock(&pnp_res_mutex);
return 0;
}
-/**
- * pnp_resource_change - change one resource
- * @resource: pointer to resource to be changed
- * @start: start of region
- * @size: size of region
- */
-void pnp_resource_change(struct resource *resource, resource_size_t start,
- resource_size_t size)
-{
- resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
- resource->start = start;
- resource->end = start + size - 1;
-}
-
-EXPORT_SYMBOL(pnp_manual_config_dev);
EXPORT_SYMBOL(pnp_start_dev);
EXPORT_SYMBOL(pnp_stop_dev);
EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev);
-EXPORT_SYMBOL(pnp_resource_change);
-EXPORT_SYMBOL(pnp_init_resource_table);
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
index 905326fcca85..2d7a1e6908be 100644
--- a/drivers/pnp/pnpacpi/Makefile
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -3,3 +3,7 @@
#
obj-y := core.o rsparser.o
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c283a9a70d83..50902773beaf 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -25,6 +25,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
+#include "../base.h"
#include "pnpacpi.h"
static int num = 0;
@@ -44,7 +45,7 @@ static struct acpi_device_id excluded_id_list[] __initdata = {
{"", 0},
};
-static inline int is_exclusive_device(struct acpi_device *dev)
+static inline int __init is_exclusive_device(struct acpi_device *dev)
{
return (!acpi_match_device_ids(dev, excluded_id_list));
}
@@ -72,40 +73,24 @@ static int __init ispnpidacpi(char *id)
return 1;
}
-static void __init pnpidacpi_to_pnpid(char *id, char *str)
+static int pnpacpi_get_resources(struct pnp_dev *dev)
{
- str[0] = id[0];
- str[1] = id[1];
- str[2] = id[2];
- str[3] = tolower(id[3]);
- str[4] = tolower(id[4]);
- str[5] = tolower(id[5]);
- str[6] = tolower(id[6]);
- str[7] = '\0';
+ dev_dbg(&dev->dev, "get resources\n");
+ return pnpacpi_parse_allocated_resource(dev);
}
-static int pnpacpi_get_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
-{
- acpi_status status;
-
- status = pnpacpi_parse_allocated_resource((acpi_handle) dev->data,
- &dev->res);
- return ACPI_FAILURE(status) ? -ENODEV : 0;
-}
-
-static int pnpacpi_set_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int pnpacpi_set_resources(struct pnp_dev *dev)
{
acpi_handle handle = dev->data;
struct acpi_buffer buffer;
- int ret = 0;
+ int ret;
acpi_status status;
- ret = pnpacpi_build_resource_template(handle, &buffer);
+ dev_dbg(&dev->dev, "set resources\n");
+ ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
- ret = pnpacpi_encode_resources(res, &buffer);
+ ret = pnpacpi_encode_resources(dev, &buffer);
if (ret) {
kfree(buffer.pointer);
return ret;
@@ -163,7 +148,6 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
{
acpi_handle temp = NULL;
acpi_status status;
- struct pnp_id *dev_id;
struct pnp_dev *dev;
status = acpi_get_handle(device->handle, "_CRS", &temp);
@@ -171,11 +155,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
is_exclusive_device(device))
return 0;
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
- if (!dev) {
- pnp_err("Out of memory");
+ dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));
+ if (!dev)
return -ENOMEM;
- }
+
dev->data = device->handle;
/* .enabled means the device can decode the resources */
dev->active = device->status.enabled;
@@ -191,44 +174,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (ACPI_SUCCESS(status))
dev->capabilities |= PNP_DISABLE;
- dev->protocol = &pnpacpi_protocol;
-
if (strlen(acpi_device_name(device)))
strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
else
strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
- dev->number = num;
-
- /* set the initial values for the PnP device */
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
- goto err;
- pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
- pnp_add_id(dev_id, dev);
-
- if (dev->active) {
- /* parse allocated resource */
- status = pnpacpi_parse_allocated_resource(device->handle,
- &dev->res);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s",
- dev_id->id);
- goto err1;
- }
- }
+ if (dev->active)
+ pnpacpi_parse_allocated_resource(dev);
- if (dev->capabilities & PNP_CONFIGURABLE) {
- status = pnpacpi_parse_resource_option_data(device->handle,
- dev);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s",
- dev_id->id);
- goto err1;
- }
- }
+ if (dev->capabilities & PNP_CONFIGURABLE)
+ pnpacpi_parse_resource_option_data(dev);
- /* parse compatible ids */
if (device->flags.compatible_ids) {
struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
int i;
@@ -236,27 +192,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
for (i = 0; i < cid_list->count; i++) {
if (!ispnpidacpi(cid_list->id[i].value))
continue;
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
- continue;
-
- pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
- pnp_add_id(dev_id, dev);
+ pnp_add_id(dev, cid_list->id[i].value);
}
}
/* clear out the damaged flags */
if (!dev->active)
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
pnp_add_device(dev);
num++;
return AE_OK;
-err1:
- kfree(dev_id);
-err:
- kfree(dev);
- return -EINVAL;
}
static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
index f28e2ed66fa3..3e60225b0227 100644
--- a/drivers/pnp/pnpacpi/pnpacpi.h
+++ b/drivers/pnp/pnpacpi/pnpacpi.h
@@ -5,8 +5,8 @@
#include <linux/acpi.h>
#include <linux/pnp.h>
-acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
-acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
-int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
-int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*);
+int pnpacpi_parse_allocated_resource(struct pnp_dev *);
+int pnpacpi_parse_resource_option_data(struct pnp_dev *);
+int pnpacpi_encode_resources(struct pnp_dev *, struct acpi_buffer *);
+int pnpacpi_build_resource_template(struct pnp_dev *, struct acpi_buffer *);
#endif
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 98cbc9f18eed..0201c8adfda7 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -21,6 +21,8 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
+#include <linux/pnp.h>
+#include "../base.h"
#include "pnpacpi.h"
#ifdef CONFIG_IA64
@@ -32,19 +34,26 @@
/*
* Allocated Resources
*/
-static int irq_flags(int triggering, int polarity)
+static int irq_flags(int triggering, int polarity, int shareable)
{
+ int flags;
+
if (triggering == ACPI_LEVEL_SENSITIVE) {
if (polarity == ACPI_ACTIVE_LOW)
- return IORESOURCE_IRQ_LOWLEVEL;
+ flags = IORESOURCE_IRQ_LOWLEVEL;
else
- return IORESOURCE_IRQ_HIGHLEVEL;
+ flags = IORESOURCE_IRQ_HIGHLEVEL;
} else {
if (polarity == ACPI_ACTIVE_LOW)
- return IORESOURCE_IRQ_LOWEDGE;
+ flags = IORESOURCE_IRQ_LOWEDGE;
else
- return IORESOURCE_IRQ_HIGHEDGE;
+ flags = IORESOURCE_IRQ_HIGHEDGE;
}
+
+ if (shareable)
+ flags |= IORESOURCE_IRQ_SHAREABLE;
+
+ return flags;
}
static void decode_irq_flags(int flag, int *triggering, int *polarity)
@@ -69,29 +78,16 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity)
}
}
-static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
+static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
u32 gsi, int triggering,
int polarity, int shareable)
{
- int i = 0;
- int irq;
+ int irq, flags;
int p, t;
- static unsigned char warned;
if (!valid_IRQ(gsi))
return;
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_IRQ)
- i++;
- if (i >= PNP_MAX_IRQ) {
- if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number"
- " of IRQ resources: %d\n", PNP_MAX_IRQ);
- warned = 1;
- }
- return;
- }
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
* 1. BIOS bug in DSDT
@@ -102,27 +98,21 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
if (triggering != t || polarity != p) {
- pnp_warn("IRQ %d override to %s, %s",
+ dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
gsi, t ? "edge":"level", p ? "low":"high");
triggering = t;
polarity = p;
}
}
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- res->irq_resource[i].flags |= irq_flags(triggering, polarity);
+ flags = irq_flags(triggering, polarity, shareable);
irq = acpi_register_gsi(gsi, triggering, polarity);
- if (irq < 0) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
-
- if (shareable)
- res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
+ if (irq >= 0)
+ pcibios_penalize_isa_irq(irq, 1);
+ else
+ flags |= IORESOURCE_DISABLED;
- res->irq_resource[i].start = irq;
- res->irq_resource[i].end = irq;
- pcibios_penalize_isa_irq(irq, 1);
+ pnp_add_irq_resource(dev, irq, flags);
}
static int dma_flags(int type, int bus_master, int transfer)
@@ -168,88 +158,36 @@ static int dma_flags(int type, int bus_master, int transfer)
return flags;
}
-static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res,
- u32 dma, int type,
- int bus_master, int transfer)
+static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
+ u64 len, int io_decode)
{
- int i = 0;
- static unsigned char warned;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- res->dma_resource[i].flags |=
- dma_flags(type, bus_master, transfer);
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start = dma;
- res->dma_resource[i].end = dma;
- } else if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number of DMA "
- "resources: %d \n", PNP_MAX_DMA);
- warned = 1;
- }
-}
+ int flags = 0;
+ u64 end = start + len - 1;
-static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
- u64 io, u64 len, int io_decode)
-{
- int i = 0;
- static unsigned char warned;
+ if (io_decode == ACPI_DECODE_16)
+ flags |= PNP_PORT_FLAG_16BITADDR;
+ if (len == 0 || end >= 0x10003)
+ flags |= IORESOURCE_DISABLED;
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (io_decode == ACPI_DECODE_16)
- res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = io;
- res->port_resource[i].end = io + len - 1;
- } else if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number of IO "
- "resources: %d \n", PNP_MAX_PORT);
- warned = 1;
- }
+ pnp_add_io_resource(dev, start, end, flags);
}
-static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
- u64 mem, u64 len,
+static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
+ u64 start, u64 len,
int write_protect)
{
- int i = 0;
- static unsigned char warned;
+ int flags = 0;
+ u64 end = start + len - 1;
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
- (i < PNP_MAX_MEM))
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- if (write_protect == ACPI_READ_WRITE_MEMORY)
- res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
-
- res->mem_resource[i].start = mem;
- res->mem_resource[i].end = mem + len - 1;
- } else if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number of mem "
- "resources: %d\n", PNP_MAX_MEM);
- warned = 1;
- }
+ if (len == 0)
+ flags |= IORESOURCE_DISABLED;
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
+ flags |= IORESOURCE_MEM_WRITEABLE;
+
+ pnp_add_mem_resource(dev, start, end, flags);
}
-static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
+static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
struct acpi_resource *res)
{
struct acpi_resource_address64 addr, *p = &addr;
@@ -257,7 +195,7 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res
status = acpi_resource_to_address64(res, p);
if (!ACPI_SUCCESS(status)) {
- pnp_warn("PnPACPI: failed to convert resource type %d",
+ dev_warn(&dev->dev, "failed to convert resource type %d\n",
res->type);
return;
}
@@ -266,11 +204,11 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res
return;
if (p->resource_type == ACPI_MEMORY_RANGE)
- pnpacpi_parse_allocated_memresource(res_table,
+ pnpacpi_parse_allocated_memresource(dev,
p->minimum, p->address_length,
p->info.mem.write_protect);
else if (p->resource_type == ACPI_IO_RANGE)
- pnpacpi_parse_allocated_ioresource(res_table,
+ pnpacpi_parse_allocated_ioresource(dev,
p->minimum, p->address_length,
p->granularity == 0xfff ? ACPI_DECODE_10 :
ACPI_DECODE_16);
@@ -279,8 +217,16 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
void *data)
{
- struct pnp_resource_table *res_table = data;
- int i;
+ struct pnp_dev *dev = data;
+ struct acpi_resource_irq *irq;
+ struct acpi_resource_dma *dma;
+ struct acpi_resource_io *io;
+ struct acpi_resource_fixed_io *fixed_io;
+ struct acpi_resource_memory24 *memory24;
+ struct acpi_resource_memory32 *memory32;
+ struct acpi_resource_fixed_memory32 *fixed_memory32;
+ struct acpi_resource_extended_irq *extended_irq;
+ int i, flags;
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
@@ -288,29 +234,33 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
* Per spec, only one interrupt per descriptor is allowed in
* _CRS, but some firmware violates this, so parse them all.
*/
- for (i = 0; i < res->data.irq.interrupt_count; i++) {
- pnpacpi_parse_allocated_irqresource(res_table,
- res->data.irq.interrupts[i],
- res->data.irq.triggering,
- res->data.irq.polarity,
- res->data.irq.sharable);
+ irq = &res->data.irq;
+ for (i = 0; i < irq->interrupt_count; i++) {
+ pnpacpi_parse_allocated_irqresource(dev,
+ irq->interrupts[i],
+ irq->triggering,
+ irq->polarity,
+ irq->sharable);
}
break;
case ACPI_RESOURCE_TYPE_DMA:
- if (res->data.dma.channel_count > 0)
- pnpacpi_parse_allocated_dmaresource(res_table,
- res->data.dma.channels[0],
- res->data.dma.type,
- res->data.dma.bus_master,
- res->data.dma.transfer);
+ dma = &res->data.dma;
+ if (dma->channel_count > 0) {
+ flags = dma_flags(dma->type, dma->bus_master,
+ dma->transfer);
+ if (dma->channels[0] == (u8) -1)
+ flags |= IORESOURCE_DISABLED;
+ pnp_add_dma_resource(dev, dma->channels[0], flags);
+ }
break;
case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_allocated_ioresource(res_table,
- res->data.io.minimum,
- res->data.io.address_length,
- res->data.io.io_decode);
+ io = &res->data.io;
+ pnpacpi_parse_allocated_ioresource(dev,
+ io->minimum,
+ io->address_length,
+ io->io_decode);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -318,9 +268,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_allocated_ioresource(res_table,
- res->data.fixed_io.address,
- res->data.fixed_io.address_length,
+ fixed_io = &res->data.fixed_io;
+ pnpacpi_parse_allocated_ioresource(dev,
+ fixed_io->address,
+ fixed_io->address_length,
ACPI_DECODE_10);
break;
@@ -331,27 +282,30 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.memory24.minimum,
- res->data.memory24.address_length,
- res->data.memory24.write_protect);
+ memory24 = &res->data.memory24;
+ pnpacpi_parse_allocated_memresource(dev,
+ memory24->minimum,
+ memory24->address_length,
+ memory24->write_protect);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.memory32.minimum,
- res->data.memory32.address_length,
- res->data.memory32.write_protect);
+ memory32 = &res->data.memory32;
+ pnpacpi_parse_allocated_memresource(dev,
+ memory32->minimum,
+ memory32->address_length,
+ memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.fixed_memory32.address,
- res->data.fixed_memory32.address_length,
- res->data.fixed_memory32.write_protect);
+ fixed_memory32 = &res->data.fixed_memory32;
+ pnpacpi_parse_allocated_memresource(dev,
+ fixed_memory32->address,
+ fixed_memory32->address_length,
+ fixed_memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_allocated_address_space(res_table, res);
+ pnpacpi_parse_allocated_address_space(dev, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
@@ -360,15 +314,16 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER)
+ extended_irq = &res->data.extended_irq;
+ if (extended_irq->producer_consumer == ACPI_PRODUCER)
return AE_OK;
- for (i = 0; i < res->data.extended_irq.interrupt_count; i++) {
- pnpacpi_parse_allocated_irqresource(res_table,
- res->data.extended_irq.interrupts[i],
- res->data.extended_irq.triggering,
- res->data.extended_irq.polarity,
- res->data.extended_irq.sharable);
+ for (i = 0; i < extended_irq->interrupt_count; i++) {
+ pnpacpi_parse_allocated_irqresource(dev,
+ extended_irq->interrupts[i],
+ extended_irq->triggering,
+ extended_irq->polarity,
+ extended_irq->sharable);
}
break;
@@ -376,24 +331,36 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
break;
default:
- pnp_warn("PnPACPI: unknown resource type %d", res->type);
+ dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
+ res->type);
return AE_ERROR;
}
return AE_OK;
}
-acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
- struct pnp_resource_table * res)
+int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
{
- /* Blank the resource table values */
- pnp_init_resource_table(res);
+ acpi_handle handle = dev->data;
+ acpi_status status;
+
+ dev_dbg(&dev->dev, "parse allocated resources\n");
- return acpi_walk_resources(handle, METHOD_NAME__CRS,
- pnpacpi_allocated_resource, res);
+ pnp_init_resources(dev);
+
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ pnpacpi_allocated_resource, dev);
+
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND)
+ dev_err(&dev->dev, "can't evaluate _CRS: %d", status);
+ return -EPERM;
+ }
+ return 0;
}
-static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
+static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_dma *p)
{
int i;
@@ -410,10 +377,11 @@ static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
dma->flags = dma_flags(p->type, p->bus_master, p->transfer);
- pnp_register_dma_resource(option, dma);
+ pnp_register_dma_resource(dev, option, dma);
}
-static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
+static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_irq *p)
{
int i;
@@ -428,12 +396,13 @@ static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
for (i = 0; i < p->interrupt_count; i++)
if (p->interrupts[i])
__set_bit(p->interrupts[i], irq->map);
- irq->flags = irq_flags(p->triggering, p->polarity);
+ irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
-static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_extended_irq *p)
{
int i;
@@ -448,12 +417,13 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
for (i = 0; i < p->interrupt_count; i++)
if (p->interrupts[i])
__set_bit(p->interrupts[i], irq->map);
- irq->flags = irq_flags(p->triggering, p->polarity);
+ irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
-static __init void pnpacpi_parse_port_option(struct pnp_option *option,
+static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_io *io)
{
struct pnp_port *port;
@@ -469,10 +439,11 @@ static __init void pnpacpi_parse_port_option(struct pnp_option *option,
port->size = io->address_length;
port->flags = ACPI_DECODE_16 == io->io_decode ?
PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
-static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_fixed_io *io)
{
struct pnp_port *port;
@@ -486,10 +457,11 @@ static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
port->size = io->address_length;
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
-static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
+static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_memory24 *p)
{
struct pnp_mem *mem;
@@ -507,10 +479,11 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
+static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_memory32 *p)
{
struct pnp_mem *mem;
@@ -528,10 +501,11 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_fixed_memory32 *p)
{
struct pnp_mem *mem;
@@ -548,10 +522,11 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpacpi_parse_address_option(struct pnp_option *option,
+static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
@@ -579,7 +554,7 @@ static __init void pnpacpi_parse_address_option(struct pnp_option *option,
mem->flags = (p->info.mem.write_protect ==
ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE
: 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
} else if (p->resource_type == ACPI_IO_RANGE) {
port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
@@ -588,7 +563,7 @@ static __init void pnpacpi_parse_address_option(struct pnp_option *option,
port->size = p->address_length;
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
}
@@ -608,11 +583,11 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
- pnpacpi_parse_irq_option(option, &res->data.irq);
+ pnpacpi_parse_irq_option(dev, option, &res->data.irq);
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnpacpi_parse_dma_option(option, &res->data.dma);
+ pnpacpi_parse_dma_option(dev, option, &res->data.dma);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -642,19 +617,22 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
/*only one EndDependentFn is allowed */
if (!parse_data->option_independent) {
- pnp_warn("PnPACPI: more than one EndDependentFn");
+ dev_warn(&dev->dev, "more than one EndDependentFn "
+ "in _PRS\n");
return AE_ERROR;
}
parse_data->option = parse_data->option_independent;
parse_data->option_independent = NULL;
+ dev_dbg(&dev->dev, "end dependent options\n");
break;
case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_port_option(option, &res->data.io);
+ pnpacpi_parse_port_option(dev, option, &res->data.io);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_fixed_port_option(option, &res->data.fixed_io);
+ pnpacpi_parse_fixed_port_option(dev, option,
+ &res->data.fixed_io);
break;
case ACPI_RESOURCE_TYPE_VENDOR:
@@ -662,57 +640,67 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_mem24_option(option, &res->data.memory24);
+ pnpacpi_parse_mem24_option(dev, option, &res->data.memory24);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_mem32_option(option, &res->data.memory32);
+ pnpacpi_parse_mem32_option(dev, option, &res->data.memory32);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_fixed_mem32_option(option,
+ pnpacpi_parse_fixed_mem32_option(dev, option,
&res->data.fixed_memory32);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_address_option(option, res);
+ pnpacpi_parse_address_option(dev, option, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnpacpi_parse_ext_irq_option(option, &res->data.extended_irq);
+ pnpacpi_parse_ext_irq_option(dev, option,
+ &res->data.extended_irq);
break;
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
break;
default:
- pnp_warn("PnPACPI: unknown resource type %d", res->type);
+ dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
+ res->type);
return AE_ERROR;
}
return AE_OK;
}
-acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle,
- struct pnp_dev *dev)
+int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
{
+ acpi_handle handle = dev->data;
acpi_status status;
struct acpipnp_parse_option_s parse_data;
+ dev_dbg(&dev->dev, "parse resource options\n");
+
parse_data.option = pnp_register_independent_option(dev);
if (!parse_data.option)
- return AE_ERROR;
+ return -ENOMEM;
+
parse_data.option_independent = parse_data.option;
parse_data.dev = dev;
status = acpi_walk_resources(handle, METHOD_NAME__PRS,
pnpacpi_option_resource, &parse_data);
- return status;
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND)
+ dev_err(&dev->dev, "can't evaluate _PRS: %d", status);
+ return -EPERM;
+ }
+ return 0;
}
static int pnpacpi_supported_resource(struct acpi_resource *res)
@@ -760,9 +748,10 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
return AE_OK;
}
-int pnpacpi_build_resource_template(acpi_handle handle,
+int pnpacpi_build_resource_template(struct pnp_dev *dev,
struct acpi_buffer *buffer)
{
+ acpi_handle handle = dev->data;
struct acpi_resource *resource;
int res_cnt = 0;
acpi_status status;
@@ -770,7 +759,7 @@ int pnpacpi_build_resource_template(acpi_handle handle,
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
pnpacpi_count_resources, &res_cnt);
if (ACPI_FAILURE(status)) {
- pnp_err("Evaluate _CRS failed");
+ dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
return -EINVAL;
}
if (!res_cnt)
@@ -779,13 +768,13 @@ int pnpacpi_build_resource_template(acpi_handle handle,
buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
if (!buffer->pointer)
return -ENOMEM;
- pnp_dbg("Res cnt %d", res_cnt);
+
resource = (struct acpi_resource *)buffer->pointer;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
pnpacpi_type_resources, &resource);
if (ACPI_FAILURE(status)) {
kfree(buffer->pointer);
- pnp_err("Evaluate _CRS failed");
+ dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
return -EINVAL;
}
/* resource will pointer the end resource now */
@@ -794,129 +783,184 @@ int pnpacpi_build_resource_template(acpi_handle handle,
return 0;
}
-static void pnpacpi_encode_irq(struct acpi_resource *resource,
+static void pnpacpi_encode_irq(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_irq *irq = &resource->data.irq;
int triggering, polarity;
decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
- resource->data.irq.triggering = triggering;
- resource->data.irq.polarity = polarity;
+ irq->triggering = triggering;
+ irq->polarity = polarity;
if (triggering == ACPI_EDGE_SENSITIVE)
- resource->data.irq.sharable = ACPI_EXCLUSIVE;
+ irq->sharable = ACPI_EXCLUSIVE;
else
- resource->data.irq.sharable = ACPI_SHARED;
- resource->data.irq.interrupt_count = 1;
- resource->data.irq.interrupts[0] = p->start;
+ irq->sharable = ACPI_SHARED;
+ irq->interrupt_count = 1;
+ irq->interrupts[0] = p->start;
+
+ dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
+ triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
+ polarity == ACPI_ACTIVE_LOW ? "low" : "high",
+ irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
}
-static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
+static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
int triggering, polarity;
decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
- resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
- resource->data.extended_irq.triggering = triggering;
- resource->data.extended_irq.polarity = polarity;
+ extended_irq->producer_consumer = ACPI_CONSUMER;
+ extended_irq->triggering = triggering;
+ extended_irq->polarity = polarity;
if (triggering == ACPI_EDGE_SENSITIVE)
- resource->data.irq.sharable = ACPI_EXCLUSIVE;
+ extended_irq->sharable = ACPI_EXCLUSIVE;
else
- resource->data.irq.sharable = ACPI_SHARED;
- resource->data.extended_irq.interrupt_count = 1;
- resource->data.extended_irq.interrupts[0] = p->start;
+ extended_irq->sharable = ACPI_SHARED;
+ extended_irq->interrupt_count = 1;
+ extended_irq->interrupts[0] = p->start;
+
+ dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
+ triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
+ polarity == ACPI_ACTIVE_LOW ? "low" : "high",
+ extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
}
-static void pnpacpi_encode_dma(struct acpi_resource *resource,
+static void pnpacpi_encode_dma(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_dma *dma = &resource->data.dma;
+
/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
case IORESOURCE_DMA_TYPEA:
- resource->data.dma.type = ACPI_TYPE_A;
+ dma->type = ACPI_TYPE_A;
break;
case IORESOURCE_DMA_TYPEB:
- resource->data.dma.type = ACPI_TYPE_B;
+ dma->type = ACPI_TYPE_B;
break;
case IORESOURCE_DMA_TYPEF:
- resource->data.dma.type = ACPI_TYPE_F;
+ dma->type = ACPI_TYPE_F;
break;
default:
- resource->data.dma.type = ACPI_COMPATIBILITY;
+ dma->type = ACPI_COMPATIBILITY;
}
switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
case IORESOURCE_DMA_8BIT:
- resource->data.dma.transfer = ACPI_TRANSFER_8;
+ dma->transfer = ACPI_TRANSFER_8;
break;
case IORESOURCE_DMA_8AND16BIT:
- resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+ dma->transfer = ACPI_TRANSFER_8_16;
break;
default:
- resource->data.dma.transfer = ACPI_TRANSFER_16;
+ dma->transfer = ACPI_TRANSFER_16;
}
- resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
- resource->data.dma.channel_count = 1;
- resource->data.dma.channels[0] = p->start;
+ dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
+ dma->channel_count = 1;
+ dma->channels[0] = p->start;
+
+ dev_dbg(&dev->dev, " encode dma %d "
+ "type %#x transfer %#x master %d\n",
+ (int) p->start, dma->type, dma->transfer, dma->bus_master);
}
-static void pnpacpi_encode_io(struct acpi_resource *resource,
+static void pnpacpi_encode_io(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_io *io = &resource->data.io;
+
/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
- resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
+ io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
ACPI_DECODE_16 : ACPI_DECODE_10;
- resource->data.io.minimum = p->start;
- resource->data.io.maximum = p->end;
- resource->data.io.alignment = 0; /* Correct? */
- resource->data.io.address_length = p->end - p->start + 1;
+ io->minimum = p->start;
+ io->maximum = p->end;
+ io->alignment = 0; /* Correct? */
+ io->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode io %#llx-%#llx decode %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ io->io_decode);
}
-static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
+static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
- resource->data.fixed_io.address = p->start;
- resource->data.fixed_io.address_length = p->end - p->start + 1;
+ struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;
+
+ fixed_io->address = p->start;
+ fixed_io->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n",
+ (unsigned long long) p->start, (unsigned long long) p->end);
}
-static void pnpacpi_encode_mem24(struct acpi_resource *resource,
+static void pnpacpi_encode_mem24(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_memory24 *memory24 = &resource->data.memory24;
+
/* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
- resource->data.memory24.write_protect =
+ memory24->write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- resource->data.memory24.minimum = p->start;
- resource->data.memory24.maximum = p->end;
- resource->data.memory24.alignment = 0;
- resource->data.memory24.address_length = p->end - p->start + 1;
+ memory24->minimum = p->start;
+ memory24->maximum = p->end;
+ memory24->alignment = 0;
+ memory24->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode mem24 %#llx-%#llx write_protect %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ memory24->write_protect);
}
-static void pnpacpi_encode_mem32(struct acpi_resource *resource,
+static void pnpacpi_encode_mem32(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
- resource->data.memory32.write_protect =
+ struct acpi_resource_memory32 *memory32 = &resource->data.memory32;
+
+ memory32->write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- resource->data.memory32.minimum = p->start;
- resource->data.memory32.maximum = p->end;
- resource->data.memory32.alignment = 0;
- resource->data.memory32.address_length = p->end - p->start + 1;
+ memory32->minimum = p->start;
+ memory32->maximum = p->end;
+ memory32->alignment = 0;
+ memory32->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx write_protect %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ memory32->write_protect);
}
-static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
+static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
- resource->data.fixed_memory32.write_protect =
+ struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;
+
+ fixed_memory32->write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- resource->data.fixed_memory32.address = p->start;
- resource->data.fixed_memory32.address_length = p->end - p->start + 1;
+ fixed_memory32->address = p->start;
+ fixed_memory32->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx "
+ "write_protect %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ fixed_memory32->write_protect);
}
-int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
- struct acpi_buffer *buffer)
+int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
{
int i = 0;
/* pnpacpi_build_resource_template allocates extra mem */
@@ -924,58 +968,48 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
struct acpi_resource *resource = buffer->pointer;
int port = 0, irq = 0, dma = 0, mem = 0;
- pnp_dbg("res cnt %d", res_cnt);
+ dev_dbg(&dev->dev, "encode %d resources\n", res_cnt);
while (i < res_cnt) {
switch (resource->type) {
case ACPI_RESOURCE_TYPE_IRQ:
- pnp_dbg("Encode irq");
- pnpacpi_encode_irq(resource,
- &res_table->irq_resource[irq]);
+ pnpacpi_encode_irq(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IRQ, irq));
irq++;
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnp_dbg("Encode dma");
- pnpacpi_encode_dma(resource,
- &res_table->dma_resource[dma]);
+ pnpacpi_encode_dma(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_DMA, dma));
dma++;
break;
case ACPI_RESOURCE_TYPE_IO:
- pnp_dbg("Encode io");
- pnpacpi_encode_io(resource,
- &res_table->port_resource[port]);
+ pnpacpi_encode_io(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnp_dbg("Encode fixed io");
- pnpacpi_encode_fixed_io(resource,
- &res_table->
- port_resource[port]);
+ pnpacpi_encode_fixed_io(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnp_dbg("Encode mem24");
- pnpacpi_encode_mem24(resource,
- &res_table->mem_resource[mem]);
+ pnpacpi_encode_mem24(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnp_dbg("Encode mem32");
- pnpacpi_encode_mem32(resource,
- &res_table->mem_resource[mem]);
+ pnpacpi_encode_mem32(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnp_dbg("Encode fixed mem32");
- pnpacpi_encode_fixed_mem32(resource,
- &res_table->
- mem_resource[mem]);
+ pnpacpi_encode_fixed_mem32(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnp_dbg("Encode ext irq");
- pnpacpi_encode_ext_irq(resource,
- &res_table->irq_resource[irq]);
+ pnpacpi_encode_ext_irq(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IRQ, irq));
irq++;
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -988,7 +1022,8 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
default: /* other type */
- pnp_warn("unknown resource type %d", resource->type);
+ dev_warn(&dev->dev, "can't encode unknown resource "
+ "type %d\n", resource->type);
return -EINVAL;
}
resource++;
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
index 3cd3ed760605..310e2b3a7710 100644
--- a/drivers/pnp/pnpbios/Makefile
+++ b/drivers/pnp/pnpbios/Makefile
@@ -5,3 +5,7 @@
pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index a8364d815222..7ff824496b39 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -7,7 +7,6 @@
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
-#include <linux/pnpbios.h>
#include <linux/device.h>
#include <linux/pnp.h>
#include <linux/mm.h>
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index a8a51500e1e9..19a4be1a9a31 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -50,7 +50,6 @@
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
-#include <linux/pnpbios.h>
#include <linux/device.h>
#include <linux/pnp.h>
#include <linux/mm.h>
@@ -69,6 +68,7 @@
#include <asm/system.h>
#include <asm/byteorder.h>
+#include "../base.h"
#include "pnpbios.h"
/*
@@ -203,8 +203,7 @@ static int pnp_dock_thread(void *unused)
#endif /* CONFIG_HOTPLUG */
-static int pnpbios_get_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int pnpbios_get_resources(struct pnp_dev *dev)
{
u8 nodenum = dev->number;
struct pnp_bios_node *node;
@@ -212,6 +211,7 @@ static int pnpbios_get_resources(struct pnp_dev *dev,
if (!pnpbios_is_dynamic(dev))
return -EPERM;
+ dev_dbg(&dev->dev, "get resources\n");
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
@@ -219,14 +219,13 @@ static int pnpbios_get_resources(struct pnp_dev *dev,
kfree(node);
return -ENODEV;
}
- pnpbios_read_resources_from_node(res, node);
+ pnpbios_read_resources_from_node(dev, node);
dev->active = pnp_is_active(dev);
kfree(node);
return 0;
}
-static int pnpbios_set_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int pnpbios_set_resources(struct pnp_dev *dev)
{
u8 nodenum = dev->number;
struct pnp_bios_node *node;
@@ -235,6 +234,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev,
if (!pnpbios_is_dynamic(dev))
return -EPERM;
+ dev_dbg(&dev->dev, "set resources\n");
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
@@ -242,7 +242,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev,
kfree(node);
return -ENODEV;
}
- if (pnpbios_write_resources_to_node(res, node) < 0) {
+ if (pnpbios_write_resources_to_node(dev, node) < 0) {
kfree(node);
return -1;
}
@@ -317,7 +317,6 @@ static int __init insert_device(struct pnp_bios_node *node)
{
struct list_head *pos;
struct pnp_dev *dev;
- struct pnp_id *dev_id;
char id[8];
/* check if the device is already added */
@@ -327,20 +326,11 @@ static int __init insert_device(struct pnp_bios_node *node)
return -1;
}
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ pnp_eisa_id_to_string(node->eisa_id & PNP_EISA_ID_MASK, id);
+ dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id);
if (!dev)
return -1;
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id) {
- kfree(dev);
- return -1;
- }
-
- dev->number = node->handle;
- pnpid32_to_pnpid(node->eisa_id, id);
- memcpy(dev_id->id, id, 7);
- pnp_add_id(dev_id, dev);
pnpbios_parse_data_stream(dev, node);
dev->active = pnp_is_active(dev);
dev->flags = node->flags;
@@ -353,11 +343,10 @@ static int __init insert_device(struct pnp_bios_node *node)
dev->capabilities |= PNP_WRITE;
if (dev->flags & PNPBIOS_REMOVABLE)
dev->capabilities |= PNP_REMOVABLE;
- dev->protocol = &pnpbios_protocol;
/* clear out the damaged flags */
if (!dev->active)
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
pnp_add_device(dev);
pnpbios_interface_attach_device(node);
diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h
index d8cb2fd1f127..b09cf6dc2075 100644
--- a/drivers/pnp/pnpbios/pnpbios.h
+++ b/drivers/pnp/pnpbios/pnpbios.h
@@ -2,6 +2,142 @@
* pnpbios.h - contains local definitions
*/
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, 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
+ */
+
+/*
+ * Return codes
+ */
+#define PNP_SUCCESS 0x00
+#define PNP_NOT_SET_STATICALLY 0x7f
+#define PNP_UNKNOWN_FUNCTION 0x81
+#define PNP_FUNCTION_NOT_SUPPORTED 0x82
+#define PNP_INVALID_HANDLE 0x83
+#define PNP_BAD_PARAMETER 0x84
+#define PNP_SET_FAILED 0x85
+#define PNP_EVENTS_NOT_PENDING 0x86
+#define PNP_SYSTEM_NOT_DOCKED 0x87
+#define PNP_NO_ISA_PNP_CARDS 0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL 0x8c
+#define PNP_USE_ESCD_SUPPORT 0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED 0x8e
+#define PNP_HARDWARE_ERROR 0x8f
+
+#define ESCD_SUCCESS 0x00
+#define ESCD_IO_ERROR_READING 0x55
+#define ESCD_INVALID 0x56
+#define ESCD_BUFFER_TOO_SMALL 0x59
+#define ESCD_NVRAM_TOO_SMALL 0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED 0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG 0x0001
+#define PNPEV_DOCK_CHANGED 0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED 0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED 0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT 0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK 0x00
+#define PNPMSG_ABORT 0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION 0x40
+#define PNPMSG_POWER_OFF 0x41
+#define PNPMSG_PNP_OS_ACTIVE 0x42
+#define PNPMSG_PNP_OS_INACTIVE 0x43
+
+/*
+ * Plug and Play BIOS flags
+ */
+#define PNPBIOS_NO_DISABLE 0x0001
+#define PNPBIOS_NO_CONFIG 0x0002
+#define PNPBIOS_OUTPUT 0x0004
+#define PNPBIOS_INPUT 0x0008
+#define PNPBIOS_BOOTABLE 0x0010
+#define PNPBIOS_DOCK 0x0020
+#define PNPBIOS_REMOVABLE 0x0040
+#define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000)
+#define pnpbios_is_dynamic(x) ((x)->flags & 0x0080)
+
+/*
+ * Function Parameters
+ */
+#define PNPMODE_STATIC 1
+#define PNPMODE_DYNAMIC 0
+
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+ __u16 no_nodes;
+ __u16 max_node_size;
+};
+struct pnp_docking_station_info {
+ __u32 location_id;
+ __u32 serial;
+ __u16 capabilities;
+};
+struct pnp_isa_config_struc {
+ __u8 revision;
+ __u8 no_csns;
+ __u16 isa_rd_data_port;
+ __u16 reserved;
+};
+struct escd_info_struc {
+ __u16 min_escd_write_size;
+ __u16 escd_size;
+ __u32 nv_storage_base;
+};
+struct pnp_bios_node {
+ __u16 size;
+ __u8 handle;
+ __u32 eisa_id;
+ __u8 type_code[3];
+ __u16 flags;
+ __u8 data[0];
+};
+#pragma pack()
+
+/* non-exported */
+extern struct pnp_dev_node_info node_info;
+
+extern int pnp_bios_dev_node_info(struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node(u8 *nodenum, char config,
+ struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node(u8 nodenum, char config,
+ struct pnp_bios_node *data);
+extern int pnp_bios_get_stat_res(char *info);
+extern int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info(struct escd_info_struc *data);
+extern int pnp_bios_read_escd(char *data, u32 nvram_base);
+extern int pnp_bios_dock_station_info(struct pnp_docking_station_info *data);
+
#pragma pack(1)
union pnp_bios_install_struct {
struct {
@@ -28,8 +164,8 @@ extern int pnp_bios_present(void);
extern int pnpbios_dont_use_current_config;
extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node);
-extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
-extern int pnpbios_write_resources_to_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
+extern int pnpbios_read_resources_from_node(struct pnp_dev *dev, struct pnp_bios_node *node);
+extern int pnpbios_write_resources_to_node(struct pnp_dev *dev, struct pnp_bios_node *node);
extern void pnpid32_to_pnpid(u32 id, char *str);
extern void pnpbios_print_status(const char * module, u16 status);
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index bb19bc957bad..b35d921bac6e 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -23,7 +23,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <linux/pnpbios.h>
+#include <linux/pnp.h>
#include <linux/init.h>
#include <asm/uaccess.h>
@@ -256,7 +256,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node *node)
*/
int __init pnpbios_proc_init(void)
{
- proc_pnp = proc_mkdir("pnp", proc_bus);
+ proc_pnp = proc_mkdir("bus/pnp", NULL);
if (!proc_pnp)
return -EIO;
proc_pnp_boot = proc_mkdir("boot", proc_pnp);
@@ -294,5 +294,5 @@ void __exit pnpbios_proc_exit(void)
remove_proc_entry("configuration_info", proc_pnp);
remove_proc_entry("devices", proc_pnp);
remove_proc_entry("boot", proc_pnp);
- remove_proc_entry("pnp", proc_bus);
+ remove_proc_entry("bus/pnp", NULL);
}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index caade3531416..5ff9a4c0447e 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -4,7 +4,6 @@
#include <linux/ctype.h>
#include <linux/pnp.h>
-#include <linux/pnpbios.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -16,6 +15,7 @@ inline void pcibios_penalize_isa_irq(int irq, int active)
}
#endif /* CONFIG_PCI */
+#include "../base.h"
#include "pnpbios.h"
/* standard resource tags */
@@ -53,97 +53,43 @@ inline void pcibios_penalize_isa_irq(int irq, int active)
* Allocated Resources
*/
-static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
- int irq)
+static void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev,
+ int start, int len)
{
- int i = 0;
-
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_IRQ)
- i++;
- if (i < PNP_MAX_IRQ) {
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- if (irq == -1) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->irq_resource[i].start =
- res->irq_resource[i].end = (unsigned long)irq;
- pcibios_penalize_isa_irq(irq, 1);
- }
-}
+ int flags = 0;
+ int end = start + len - 1;
-static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
- int dma)
-{
- int i = 0;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start =
- res->dma_resource[i].end = (unsigned long)dma;
- }
-}
+ if (len <= 0 || end >= 0x10003)
+ flags |= IORESOURCE_DISABLED;
-static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
- int io, int len)
-{
- int i = 0;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = (unsigned long)io;
- res->port_resource[i].end = (unsigned long)(io + len - 1);
- }
+ pnp_add_io_resource(dev, start, end, flags);
}
-static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
- int mem, int len)
+static void pnpbios_parse_allocated_memresource(struct pnp_dev *dev,
+ int start, int len)
{
- int i = 0;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_MEM)
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->mem_resource[i].start = (unsigned long)mem;
- res->mem_resource[i].end = (unsigned long)(mem + len - 1);
- }
+ int flags = 0;
+ int end = start + len - 1;
+
+ if (len <= 0)
+ flags |= IORESOURCE_DISABLED;
+
+ pnp_add_mem_resource(dev, start, end, flags);
}
-static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
- unsigned char *end,
- struct
- pnp_resource_table
- *res)
+static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
+ unsigned char *p,
+ unsigned char *end)
{
unsigned int len, tag;
- int io, size, mask, i;
+ int io, size, mask, i, flags;
if (!p)
return NULL;
- /* Blank the resource table values */
- pnp_init_resource_table(res);
+ dev_dbg(&dev->dev, "parse allocated resources\n");
+
+ pnp_init_resources(dev);
while ((char *)p < (char *)end) {
@@ -163,7 +109,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
goto len_err;
io = *(short *)&p[4];
size = *(short *)&p[10];
- pnpbios_parse_allocated_memresource(res, io, size);
+ pnpbios_parse_allocated_memresource(dev, io, size);
break;
case LARGE_TAG_ANSISTR:
@@ -179,7 +125,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
goto len_err;
io = *(int *)&p[4];
size = *(int *)&p[16];
- pnpbios_parse_allocated_memresource(res, io, size);
+ pnpbios_parse_allocated_memresource(dev, io, size);
break;
case LARGE_TAG_FIXEDMEM32:
@@ -187,29 +133,37 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
goto len_err;
io = *(int *)&p[4];
size = *(int *)&p[8];
- pnpbios_parse_allocated_memresource(res, io, size);
+ pnpbios_parse_allocated_memresource(dev, io, size);
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
+ flags = 0;
io = -1;
mask = p[1] + p[2] * 256;
for (i = 0; i < 16; i++, mask = mask >> 1)
if (mask & 0x01)
io = i;
- pnpbios_parse_allocated_irqresource(res, io);
+ if (io != -1)
+ pcibios_penalize_isa_irq(io, 1);
+ else
+ flags = IORESOURCE_DISABLED;
+ pnp_add_irq_resource(dev, io, flags);
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
+ flags = 0;
io = -1;
mask = p[1];
for (i = 0; i < 8; i++, mask = mask >> 1)
if (mask & 0x01)
io = i;
- pnpbios_parse_allocated_dmaresource(res, io);
+ if (io == -1)
+ flags = IORESOURCE_DISABLED;
+ pnp_add_dma_resource(dev, io, flags);
break;
case SMALL_TAG_PORT:
@@ -217,7 +171,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
goto len_err;
io = p[2] + p[3] * 256;
size = p[7];
- pnpbios_parse_allocated_ioresource(res, io, size);
+ pnpbios_parse_allocated_ioresource(dev, io, size);
break;
case SMALL_TAG_VENDOR:
@@ -229,7 +183,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
goto len_err;
io = p[1] + p[2] * 256;
size = p[3];
- pnpbios_parse_allocated_ioresource(res, io, size);
+ pnpbios_parse_allocated_ioresource(dev, io, size);
break;
case SMALL_TAG_END:
@@ -239,9 +193,8 @@ static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -252,8 +205,7 @@ len_err:
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -262,7 +214,8 @@ len_err:
* Resource Configuration Options
*/
-static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
+static __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -275,10 +228,11 @@ static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
mem->align = (p[9] << 8) | p[8];
mem->size = ((p[11] << 8) | p[10]) << 8;
mem->flags = p[3];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
+static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -291,10 +245,11 @@ static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
mem->flags = p[3];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -306,11 +261,12 @@ static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
mem->align = 0;
mem->flags = p[3];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_irq *irq;
unsigned long bits;
@@ -324,11 +280,12 @@ static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
irq->flags = p[3];
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
-static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_dma_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_dma *dma;
@@ -337,10 +294,11 @@ static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
return;
dma->map = p[1];
dma->flags = p[2];
- pnp_register_dma_resource(option, dma);
+ pnp_register_dma_resource(dev, option, dma);
}
-static __init void pnpbios_parse_port_option(unsigned char *p, int size,
+static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_port *port;
@@ -353,10 +311,11 @@ static __init void pnpbios_parse_port_option(unsigned char *p, int size,
port->align = p[6];
port->size = p[7];
port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
-static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_port *port;
@@ -368,7 +327,7 @@ static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
port->size = p[3];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
static __init unsigned char *
@@ -382,6 +341,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
if (!p)
return NULL;
+ dev_dbg(&dev->dev, "parse resource options\n");
+
option_independent = option = pnp_register_independent_option(dev);
if (!option)
return NULL;
@@ -402,37 +363,37 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
- pnpbios_parse_mem_option(p, len, option);
+ pnpbios_parse_mem_option(dev, p, len, option);
break;
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
- pnpbios_parse_mem32_option(p, len, option);
+ pnpbios_parse_mem32_option(dev, p, len, option);
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
- pnpbios_parse_fixed_mem32_option(p, len, option);
+ pnpbios_parse_fixed_mem32_option(dev, p, len, option);
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
- pnpbios_parse_irq_option(p, len, option);
+ pnpbios_parse_irq_option(dev, p, len, option);
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
- pnpbios_parse_dma_option(p, len, option);
+ pnpbios_parse_dma_option(dev, p, len, option);
break;
case SMALL_TAG_PORT:
if (len != 7)
goto len_err;
- pnpbios_parse_port_option(p, len, option);
+ pnpbios_parse_port_option(dev, p, len, option);
break;
case SMALL_TAG_VENDOR:
@@ -442,7 +403,7 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
case SMALL_TAG_FIXEDPORT:
if (len != 3)
goto len_err;
- pnpbios_parse_fixed_port_option(p, len, option);
+ pnpbios_parse_fixed_port_option(dev, p, len, option);
break;
case SMALL_TAG_STARTDEP:
@@ -460,9 +421,10 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
if (len != 0)
goto len_err;
if (option_independent == option)
- printk(KERN_WARNING
- "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
+ dev_warn(&dev->dev, "missing "
+ "SMALL_TAG_STARTDEP tag\n");
option = option_independent;
+ dev_dbg(&dev->dev, "end dependent options\n");
break;
case SMALL_TAG_END:
@@ -470,9 +432,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -483,8 +444,7 @@ len_err:
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -493,32 +453,12 @@ len_err:
* Compatible Device IDs
*/
-#define HEX(id,a) hex[((id)>>a) & 15]
-#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
-
-void pnpid32_to_pnpid(u32 id, char *str)
-{
- const char *hex = "0123456789abcdef";
-
- id = be32_to_cpu(id);
- str[0] = CHAR(id, 26);
- str[1] = CHAR(id, 21);
- str[2] = CHAR(id, 16);
- str[3] = HEX(id, 12);
- str[4] = HEX(id, 8);
- str[5] = HEX(id, 4);
- str[6] = HEX(id, 0);
- str[7] = '\0';
-}
-
-#undef CHAR
-#undef HEX
-
static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
unsigned char *end,
struct pnp_dev *dev)
{
int len, tag;
+ u32 eisa_id;
char id[8];
struct pnp_id *dev_id;
@@ -548,13 +488,11 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
case SMALL_TAG_COMPATDEVID: /* compatible ID */
if (len != 4)
goto len_err;
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24;
+ pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id);
+ dev_id = pnp_add_id(dev, id);
if (!dev_id)
return NULL;
- 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);
break;
case SMALL_TAG_END:
@@ -564,9 +502,8 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -577,8 +514,7 @@ len_err:
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -587,7 +523,8 @@ len_err:
* Allocated Resource Encoding
*/
-static void pnpbios_encode_mem(unsigned char *p, struct resource *res)
+static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -598,9 +535,13 @@ static void pnpbios_encode_mem(unsigned char *p, struct resource *res)
p[7] = ((base >> 8) >> 8) & 0xff;
p[10] = (len >> 8) & 0xff;
p[11] = ((len >> 8) >> 8) & 0xff;
+
+ dev_dbg(&dev->dev, " encode mem %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_mem32(unsigned char *p, struct resource *res)
+static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -617,9 +558,13 @@ static void pnpbios_encode_mem32(unsigned char *p, struct resource *res)
p[17] = (len >> 8) & 0xff;
p[18] = (len >> 16) & 0xff;
p[19] = (len >> 24) & 0xff;
+
+ dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res)
+static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -632,26 +577,38 @@ static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res)
p[9] = (len >> 8) & 0xff;
p[10] = (len >> 16) & 0xff;
p[11] = (len >> 24) & 0xff;
+
+ dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_irq(unsigned char *p, struct resource *res)
+static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long map = 0;
map = 1 << res->start;
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
+
+ dev_dbg(&dev->dev, " encode irq %llu\n",
+ (unsigned long long)res->start);
}
-static void pnpbios_encode_dma(unsigned char *p, struct resource *res)
+static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long map = 0;
map = 1 << res->start;
p[1] = map & 0xff;
+
+ dev_dbg(&dev->dev, " encode dma %llu\n",
+ (unsigned long long)res->start);
}
-static void pnpbios_encode_port(unsigned char *p, struct resource *res)
+static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -661,9 +618,13 @@ static void pnpbios_encode_port(unsigned char *p, struct resource *res)
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[7] = len & 0xff;
+
+ dev_dbg(&dev->dev, " encode io %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res)
+static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -671,13 +632,15 @@ static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res)
p[1] = base & 0xff;
p[2] = (base >> 8) & 0xff;
p[3] = len & 0xff;
+
+ dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p,
- unsigned char *end,
- struct
- pnp_resource_table
- *res)
+static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev
+ *dev,
+ unsigned char *p,
+ unsigned char *end)
{
unsigned int len, tag;
int port = 0, irq = 0, dma = 0, mem = 0;
@@ -701,42 +664,48 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p,
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
- pnpbios_encode_mem(p, &res->mem_resource[mem]);
+ pnpbios_encode_mem(dev, p,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
- pnpbios_encode_mem32(p, &res->mem_resource[mem]);
+ pnpbios_encode_mem32(dev, p,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
- pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]);
+ pnpbios_encode_fixed_mem32(dev, p,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
- pnpbios_encode_irq(p, &res->irq_resource[irq]);
+ pnpbios_encode_irq(dev, p,
+ pnp_get_resource(dev, IORESOURCE_IRQ, irq));
irq++;
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
- pnpbios_encode_dma(p, &res->dma_resource[dma]);
+ pnpbios_encode_dma(dev, p,
+ pnp_get_resource(dev, IORESOURCE_DMA, dma));
dma++;
break;
case SMALL_TAG_PORT:
if (len != 7)
goto len_err;
- pnpbios_encode_port(p, &res->port_resource[port]);
+ pnpbios_encode_port(dev, p,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
@@ -747,7 +716,8 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p,
case SMALL_TAG_FIXEDPORT:
if (len != 3)
goto len_err;
- pnpbios_encode_fixed_port(p, &res->port_resource[port]);
+ pnpbios_encode_fixed_port(dev, p,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
@@ -758,9 +728,8 @@ static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p,
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -771,8 +740,7 @@ len_err:
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -787,7 +755,7 @@ int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
- p = pnpbios_parse_allocated_resource_data(p, end, &dev->res);
+ p = pnpbios_parse_allocated_resource_data(dev, p, end);
if (!p)
return -EIO;
p = pnpbios_parse_resource_option_data(p, end, dev);
@@ -799,25 +767,25 @@ int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
return 0;
}
-int pnpbios_read_resources_from_node(struct pnp_resource_table *res,
+int pnpbios_read_resources_from_node(struct pnp_dev *dev,
struct pnp_bios_node *node)
{
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
- p = pnpbios_parse_allocated_resource_data(p, end, res);
+ p = pnpbios_parse_allocated_resource_data(dev, p, end);
if (!p)
return -EIO;
return 0;
}
-int pnpbios_write_resources_to_node(struct pnp_resource_table *res,
+int pnpbios_write_resources_to_node(struct pnp_dev *dev,
struct pnp_bios_node *node)
{
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
- p = pnpbios_encode_allocated_resource_data(p, end, res);
+ p = pnpbios_encode_allocated_resource_data(dev, p, end);
if (!p)
return -EIO;
return 0;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e4daf4635c48..e2b7de4cb05e 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -111,12 +111,120 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
dev_info(&dev->dev, "SB audio device quirk - increased port range\n");
}
+static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev)
+{
+ struct pnp_option *head = NULL;
+ struct pnp_option *prev = NULL;
+ struct pnp_option *res;
+
+ /*
+ * Build a functional IRQ-less variant of each MPU option.
+ */
+
+ for (res = dev->dependent; res; res = res->next) {
+ struct pnp_option *curr;
+ struct pnp_port *port;
+ struct pnp_port *copy;
+
+ port = res->port;
+ if (!port || !res->irq)
+ continue;
+
+ copy = pnp_alloc(sizeof *copy);
+ if (!copy)
+ break;
+
+ copy->min = port->min;
+ copy->max = port->max;
+ copy->align = port->align;
+ copy->size = port->size;
+ copy->flags = port->flags;
+
+ curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
+ if (!curr) {
+ kfree(copy);
+ break;
+ }
+ curr->port = copy;
+
+ if (prev)
+ prev->next = curr;
+ else
+ head = curr;
+ prev = curr;
+ }
+ if (head)
+ dev_info(&dev->dev, "adding IRQ-less MPU options\n");
+
+ return head;
+}
+
+static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
+{
+ struct pnp_option *res;
+ struct pnp_irq *irq;
+
+ /*
+ * Distribute the independent IRQ over the dependent options
+ */
+
+ res = dev->independent;
+ if (!res)
+ return;
+
+ irq = res->irq;
+ if (!irq || irq->next)
+ return;
+
+ res = dev->dependent;
+ if (!res)
+ return;
+
+ while (1) {
+ struct pnp_irq *copy;
+
+ copy = pnp_alloc(sizeof *copy);
+ if (!copy)
+ break;
+
+ memcpy(copy->map, irq->map, sizeof copy->map);
+ copy->flags = irq->flags;
+
+ copy->next = res->irq; /* Yes, this is NULL */
+ res->irq = copy;
+
+ if (!res->next)
+ break;
+ res = res->next;
+ }
+ kfree(irq);
+
+ res->next = quirk_isapnp_mpu_options(dev);
+
+ res = dev->independent;
+ res->irq = NULL;
+}
+
+static void quirk_isapnp_mpu_resources(struct pnp_dev *dev)
+{
+ struct pnp_option *res;
+
+ res = dev->dependent;
+ if (!res)
+ return;
+
+ while (res->next)
+ res = res->next;
+
+ res->next = quirk_isapnp_mpu_options(dev);
+}
#include <linux/pci.h>
static void quirk_system_pci_resources(struct pnp_dev *dev)
{
struct pci_dev *pdev = NULL;
+ struct resource *res;
resource_size_t pnp_start, pnp_end, pci_start, pci_end;
int i, j;
@@ -137,13 +245,15 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
pci_start = pci_resource_start(pdev, i);
pci_end = pci_resource_end(pdev, i);
- for (j = 0; j < PNP_MAX_MEM; j++) {
- if (!pnp_mem_valid(dev, j) ||
- pnp_mem_len(dev, j) == 0)
+ for (j = 0;
+ (res = pnp_get_resource(dev, IORESOURCE_MEM, j));
+ j++) {
+ if (res->flags & IORESOURCE_UNSET ||
+ (res->start == 0 && res->end == 0))
continue;
- pnp_start = pnp_mem_start(dev, j);
- pnp_end = pnp_mem_end(dev, j);
+ pnp_start = res->start;
+ pnp_end = res->end;
/*
* If the PNP region doesn't overlap the PCI
@@ -176,7 +286,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
pci_name(pdev), i,
(unsigned long long) pci_start,
(unsigned long long) pci_end);
- pnp_mem_flags(dev, j) = 0;
+ res->flags = 0;
}
}
}
@@ -202,6 +312,11 @@ static struct pnp_fixup pnp_fixups[] = {
{"CTL0043", quirk_sb16audio_resources},
{"CTL0044", quirk_sb16audio_resources},
{"CTL0045", quirk_sb16audio_resources},
+ /* Add IRQ-less MPU options */
+ {"ADS7151", quirk_ad1815_mpu_resources},
+ {"ADS7181", quirk_isapnp_mpu_resources},
+ {"AZT0002", quirk_isapnp_mpu_resources},
+ /* PnP resources that might overlap PCI BARs */
{"PNP0c01", quirk_system_pci_resources},
{"PNP0c02", quirk_system_pci_resources},
{""}
@@ -209,20 +324,15 @@ static struct pnp_fixup pnp_fixups[] = {
void pnp_fixup_device(struct pnp_dev *dev)
{
- int i = 0;
- void (*quirk)(struct pnp_dev *);
-
- while (*pnp_fixups[i].id) {
- if (compare_pnp_id(dev->id, pnp_fixups[i].id)) {
- quirk = pnp_fixups[i].quirk_function;
+ struct pnp_fixup *f;
+ for (f = pnp_fixups; *f->id; f++) {
+ if (!compare_pnp_id(dev->id, f->id))
+ continue;
#ifdef DEBUG
- dev_dbg(&dev->dev, "calling ");
- print_fn_descriptor_symbol("%s()\n",
- (unsigned long) *quirk);
+ dev_dbg(&dev->dev, "%s: calling ", f->id);
+ print_fn_descriptor_symbol("%s\n", f->quirk_function);
#endif
- (*quirk)(dev);
- }
- i++;
+ f->quirk_function(dev);
}
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index e50ebcffb962..390b50096e30 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -28,7 +28,7 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some
* option registration
*/
-static struct pnp_option *pnp_build_option(int priority)
+struct pnp_option *pnp_build_option(int priority)
{
struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
@@ -53,6 +53,8 @@ struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
if (dev->independent)
dev_err(&dev->dev, "independent resource already registered\n");
dev->independent = option;
+
+ dev_dbg(&dev->dev, "new independent option\n");
return option;
}
@@ -70,12 +72,18 @@ struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
parent->next = option;
} else
dev->dependent = option;
+
+ dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority);
return option;
}
-int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
+int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_irq *data)
{
struct pnp_irq *ptr;
+#ifdef DEBUG
+ char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */
+#endif
ptr = option->irq;
while (ptr && ptr->next)
@@ -94,10 +102,17 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
pcibios_penalize_isa_irq(i, 0);
}
#endif
+
+#ifdef DEBUG
+ bitmap_scnprintf(buf, sizeof(buf), data->map, PNP_IRQ_NR);
+ dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf,
+ data->flags);
+#endif
return 0;
}
-int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
+int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_dma *data)
{
struct pnp_dma *ptr;
@@ -109,10 +124,13 @@ int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
else
option->dma = data;
+ dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map,
+ data->flags);
return 0;
}
-int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
+int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_port *data)
{
struct pnp_port *ptr;
@@ -124,10 +142,14 @@ int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
else
option->port = data;
+ dev_dbg(&dev->dev, " io "
+ "min %#x max %#x align %d size %d flags %#x\n",
+ data->min, data->max, data->align, data->size, data->flags);
return 0;
}
-int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
+int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_mem *data)
{
struct pnp_mem *ptr;
@@ -138,6 +160,10 @@ int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
ptr->next = data;
else
option->mem = data;
+
+ dev_dbg(&dev->dev, " mem "
+ "min %#x max %#x align %d size %d flags %#x\n",
+ data->min, data->max, data->align, data->size, data->flags);
return 0;
}
@@ -213,17 +239,18 @@ void pnp_free_option(struct pnp_option *option)
#define cannot_compare(flags) \
((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
-int pnp_check_port(struct pnp_dev *dev, int idx)
+int pnp_check_port(struct pnp_dev *dev, struct resource *res)
{
- int tmp;
+ int i;
struct pnp_dev *tdev;
+ struct resource *tres;
resource_size_t *port, *end, *tport, *tend;
- port = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
+ port = &res->start;
+ end = &res->end;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.port_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is already in use, skip if the
@@ -234,18 +261,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx)
}
/* check if the resource is reserved */
- for (tmp = 0; tmp < 8; tmp++) {
- int rport = pnp_reserve_io[tmp << 1];
- int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
+ for (i = 0; i < 8; i++) {
+ int rport = pnp_reserve_io[i << 1];
+ int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
if (ranged_conflict(port, end, &rport, &rend))
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
- if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
- tport = &dev->res.port_resource[tmp].start;
- tend = &dev->res.port_resource[tmp].end;
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_IO) {
+ tport = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(port, end, tport, tend))
return 0;
}
@@ -255,13 +282,14 @@ int pnp_check_port(struct pnp_dev *dev, int idx)
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
- if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
- if (cannot_compare
- (tdev->res.port_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
+ i++) {
+ if (tres->flags & IORESOURCE_IO) {
+ if (cannot_compare(tres->flags))
continue;
- tport = &tdev->res.port_resource[tmp].start;
- tend = &tdev->res.port_resource[tmp].end;
+ tport = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(port, end, tport, tend))
return 0;
}
@@ -271,17 +299,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx)
return 1;
}
-int pnp_check_mem(struct pnp_dev *dev, int idx)
+int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
{
- int tmp;
+ int i;
struct pnp_dev *tdev;
+ struct resource *tres;
resource_size_t *addr, *end, *taddr, *tend;
- addr = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
+ addr = &res->start;
+ end = &res->end;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.mem_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is already in use, skip if the
@@ -292,18 +321,18 @@ int pnp_check_mem(struct pnp_dev *dev, int idx)
}
/* check if the resource is reserved */
- for (tmp = 0; tmp < 8; tmp++) {
- int raddr = pnp_reserve_mem[tmp << 1];
- int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
+ for (i = 0; i < 8; i++) {
+ int raddr = pnp_reserve_mem[i << 1];
+ int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
if (ranged_conflict(addr, end, &raddr, &rend))
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
- if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
- taddr = &dev->res.mem_resource[tmp].start;
- tend = &dev->res.mem_resource[tmp].end;
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_MEM) {
+ taddr = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(addr, end, taddr, tend))
return 0;
}
@@ -313,13 +342,14 @@ int pnp_check_mem(struct pnp_dev *dev, int idx)
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
- if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
- if (cannot_compare
- (tdev->res.mem_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
+ i++) {
+ if (tres->flags & IORESOURCE_MEM) {
+ if (cannot_compare(tres->flags))
continue;
- taddr = &tdev->res.mem_resource[tmp].start;
- tend = &tdev->res.mem_resource[tmp].end;
+ taddr = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(addr, end, taddr, tend))
return 0;
}
@@ -334,14 +364,17 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int pnp_check_irq(struct pnp_dev *dev, int idx)
+int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
{
- int tmp;
+ int i;
struct pnp_dev *tdev;
- resource_size_t *irq = &dev->res.irq_resource[idx].start;
+ struct resource *tres;
+ resource_size_t *irq;
+
+ irq = &res->start;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.irq_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is valid */
@@ -349,15 +382,15 @@ int pnp_check_irq(struct pnp_dev *dev, int idx)
return 0;
/* check if the resource is reserved */
- for (tmp = 0; tmp < 16; tmp++) {
- if (pnp_reserve_irq[tmp] == *irq)
+ for (i = 0; i < 16; i++) {
+ if (pnp_reserve_irq[i] == *irq)
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
- if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
- if (dev->res.irq_resource[tmp].start == *irq)
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_IRQ) {
+ if (tres->start == *irq)
return 0;
}
}
@@ -388,12 +421,13 @@ int pnp_check_irq(struct pnp_dev *dev, int idx)
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
- if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
- if (cannot_compare
- (tdev->res.irq_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
+ i++) {
+ if (tres->flags & IORESOURCE_IRQ) {
+ if (cannot_compare(tres->flags))
continue;
- if ((tdev->res.irq_resource[tmp].start == *irq))
+ if (tres->start == *irq)
return 0;
}
}
@@ -402,15 +436,18 @@ int pnp_check_irq(struct pnp_dev *dev, int idx)
return 1;
}
-int pnp_check_dma(struct pnp_dev *dev, int idx)
+int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
{
#ifndef CONFIG_IA64
- int tmp;
+ int i;
struct pnp_dev *tdev;
- resource_size_t *dma = &dev->res.dma_resource[idx].start;
+ struct resource *tres;
+ resource_size_t *dma;
+
+ dma = &res->start;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.dma_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is valid */
@@ -418,15 +455,15 @@ int pnp_check_dma(struct pnp_dev *dev, int idx)
return 0;
/* check if the resource is reserved */
- for (tmp = 0; tmp < 8; tmp++) {
- if (pnp_reserve_dma[tmp] == *dma)
+ for (i = 0; i < 8; i++) {
+ if (pnp_reserve_dma[i] == *dma)
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
- if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
- if (dev->res.dma_resource[tmp].start == *dma)
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_DMA) {
+ if (tres->start == *dma)
return 0;
}
}
@@ -443,12 +480,13 @@ int pnp_check_dma(struct pnp_dev *dev, int idx)
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
- if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
- if (cannot_compare
- (tdev->res.dma_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
+ i++) {
+ if (tres->flags & IORESOURCE_DMA) {
+ if (cannot_compare(tres->flags))
continue;
- if ((tdev->res.dma_resource[tmp].start == *dma))
+ if (tres->start == *dma)
return 0;
}
}
@@ -461,6 +499,193 @@ int pnp_check_dma(struct pnp_dev *dev, int idx)
#endif
}
+struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev,
+ unsigned int type, unsigned int num)
+{
+ struct pnp_resource_table *res = dev->res;
+
+ switch (type) {
+ case IORESOURCE_IO:
+ if (num >= PNP_MAX_PORT)
+ return NULL;
+ return &res->port[num];
+ case IORESOURCE_MEM:
+ if (num >= PNP_MAX_MEM)
+ return NULL;
+ return &res->mem[num];
+ case IORESOURCE_IRQ:
+ if (num >= PNP_MAX_IRQ)
+ return NULL;
+ return &res->irq[num];
+ case IORESOURCE_DMA:
+ if (num >= PNP_MAX_DMA)
+ return NULL;
+ return &res->dma[num];
+ }
+ return NULL;
+}
+
+struct resource *pnp_get_resource(struct pnp_dev *dev,
+ unsigned int type, unsigned int num)
+{
+ struct pnp_resource *pnp_res;
+
+ pnp_res = pnp_get_pnp_resource(dev, type, num);
+ if (pnp_res)
+ return &pnp_res->res;
+
+ return NULL;
+}
+EXPORT_SYMBOL(pnp_get_resource);
+
+static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev, int type)
+{
+ struct pnp_resource *pnp_res;
+ int i;
+
+ switch (type) {
+ case IORESOURCE_IO:
+ for (i = 0; i < PNP_MAX_PORT; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ case IORESOURCE_MEM:
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ case IORESOURCE_IRQ:
+ for (i = 0; i < PNP_MAX_IRQ; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ case IORESOURCE_DMA:
+ for (i = 0; i < PNP_MAX_DMA; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ }
+ return NULL;
+}
+
+struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
+ int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_IRQ);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for IRQ %d\n",
+ irq);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_IRQ | flags;
+ res->start = irq;
+ res->end = irq;
+
+ dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags);
+ return pnp_res;
+}
+
+struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
+ int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_DMA);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for DMA %d\n",
+ dma);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_DMA | flags;
+ res->start = dma;
+ res->end = dma;
+
+ dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags);
+ return pnp_res;
+}
+
+struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_IO);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for IO "
+ "%#llx-%#llx\n",(unsigned long long) start,
+ (unsigned long long) end);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_IO | flags;
+ res->start = start;
+ res->end = end;
+
+ dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
+ (unsigned long long) start, (unsigned long long) end, flags);
+ return pnp_res;
+}
+
+struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_MEM);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for MEM "
+ "%#llx-%#llx\n",(unsigned long long) start,
+ (unsigned long long) end);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_MEM | flags;
+ res->start = start;
+ res->end = end;
+
+ dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
+ (unsigned long long) start, (unsigned long long) end, flags);
+ return pnp_res;
+}
+
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
static int __init pnp_setup_reserve_irq(char *str)
{
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 13c608f5fb30..95b076c18c07 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -25,3 +25,66 @@ int pnp_is_active(struct pnp_dev *dev)
}
EXPORT_SYMBOL(pnp_is_active);
+
+/*
+ * Functionally similar to acpi_ex_eisa_id_to_string(), but that's
+ * buried in the ACPI CA, and we can't depend on it being present.
+ */
+void pnp_eisa_id_to_string(u32 id, char *str)
+{
+ id = be32_to_cpu(id);
+
+ /*
+ * According to the specs, the first three characters are five-bit
+ * compressed ASCII, and the left-over high order bit should be zero.
+ * However, the Linux ISAPNP code historically used six bits for the
+ * first character, and there seem to be IDs that depend on that,
+ * e.g., "nEC8241" in the Linux 8250_pnp serial driver and the
+ * FreeBSD sys/pc98/cbus/sio_cbus.c driver.
+ */
+ str[0] = 'A' + ((id >> 26) & 0x3f) - 1;
+ str[1] = 'A' + ((id >> 21) & 0x1f) - 1;
+ str[2] = 'A' + ((id >> 16) & 0x1f) - 1;
+ str[3] = hex_asc_hi(id >> 8);
+ str[4] = hex_asc_lo(id >> 8);
+ str[5] = hex_asc_hi(id);
+ str[6] = hex_asc_lo(id);
+ str[7] = '\0';
+}
+
+void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
+{
+#ifdef DEBUG
+ struct resource *res;
+ int i;
+
+ dev_dbg(&dev->dev, "current resources: %s\n", desc);
+
+ for (i = 0; i < PNP_MAX_IRQ; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_IRQ, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " irq %lld flags %#lx\n",
+ (unsigned long long) res->start, res->flags);
+ }
+ for (i = 0; i < PNP_MAX_DMA; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_DMA, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " dma %lld flags %#lx\n",
+ (unsigned long long) res->start, res->flags);
+ }
+ for (i = 0; i < PNP_MAX_PORT; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_IO, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " io %#llx-%#llx flags %#lx\n",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
+ }
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_MEM, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " mem %#llx-%#llx flags %#lx\n",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
+ }
+#endif
+}
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index 55c4563986b3..9c2496dbeee4 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -56,14 +56,15 @@ static void reserve_range(struct pnp_dev *dev, resource_size_t start,
static void reserve_resources_of_dev(struct pnp_dev *dev)
{
+ struct resource *res;
int i;
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_port_valid(dev, i))
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
+ if (res->flags & IORESOURCE_UNSET)
continue;
- if (pnp_port_start(dev, i) == 0)
+ if (res->start == 0)
continue; /* disabled */
- if (pnp_port_start(dev, i) < 0x100)
+ if (res->start < 0x100)
/*
* Below 0x100 is only standard PC hardware
* (pics, kbd, timer, dma, ...)
@@ -73,19 +74,17 @@ static void reserve_resources_of_dev(struct pnp_dev *dev)
* So, do nothing
*/
continue;
- if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
+ if (res->end < res->start)
continue; /* invalid */
- reserve_range(dev, pnp_port_start(dev, i),
- pnp_port_end(dev, i), 1);
+ reserve_range(dev, res->start, res->end, 1);
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_mem_valid(dev, i))
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
+ if (res->flags & IORESOURCE_UNSET)
continue;
- reserve_range(dev, pnp_mem_start(dev, i),
- pnp_mem_end(dev, i), 0);
+ reserve_range(dev, res->start, res->end, 0);
}
}
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index bdb9b7285b3d..71be36f18709 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -262,7 +262,7 @@ static void ds2760_battery_work(struct work_struct *work)
struct ds2760_device_info, monitor_work.work);
const int interval = HZ * 60;
- dev_dbg(di->dev, "%s\n", __FUNCTION__);
+ dev_dbg(di->dev, "%s\n", __func__);
ds2760_battery_update_status(di);
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
@@ -275,7 +275,7 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy)
{
struct ds2760_device_info *di = to_ds2760_device_info(psy);
- dev_dbg(di->dev, "%s\n", __FUNCTION__);
+ dev_dbg(di->dev, "%s\n", __func__);
cancel_delayed_work(&di->monitor_work);
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index af7a231092a4..ab1e8289f07f 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -315,7 +315,6 @@ static int __init olpc_bat_init(void)
if (ret)
goto battery_failed;
- olpc_register_battery_callback(&olpc_battery_trigger_uevent);
goto success;
battery_failed:
@@ -328,7 +327,6 @@ success:
static void __exit olpc_bat_exit(void)
{
- olpc_deregister_battery_callback();
power_supply_unregister(&olpc_bat);
power_supply_unregister(&olpc_ac);
platform_device_unregister(bat_pdev);
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index c8aa55b81fd8..82810b7bff9c 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -209,6 +209,12 @@ static int pda_power_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
+ if (pdata->init) {
+ ret = pdata->init(dev);
+ if (ret < 0)
+ goto init_failed;
+ }
+
update_status();
update_charger();
@@ -298,6 +304,9 @@ ac_irq_failed:
if (pdata->is_ac_online)
power_supply_unregister(&pda_psy_ac);
ac_supply_failed:
+ if (pdata->exit)
+ pdata->exit(dev);
+init_failed:
wrongid:
return ret;
}
@@ -318,6 +327,8 @@ static int pda_power_remove(struct platform_device *pdev)
power_supply_unregister(&pda_psy_usb);
if (pdata->is_ac_online)
power_supply_unregister(&pda_psy_ac);
+ if (pdata->exit)
+ pdata->exit(dev);
return 0;
}
diff --git a/drivers/power/pmu_battery.c b/drivers/power/pmu_battery.c
index 60a8cf3a0431..9346a862f1f2 100644
--- a/drivers/power/pmu_battery.c
+++ b/drivers/power/pmu_battery.c
@@ -159,7 +159,7 @@ static int __init pmu_bat_init(void)
if (!pbat)
break;
- sprintf(pbat->name, "PMU battery %d", i);
+ sprintf(pbat->name, "PMU_battery_%d", i);
pbat->bat.name = pbat->name;
pbat->bat.properties = pmu_bat_props;
pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 03d6a38464ef..138dd76ee347 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -39,7 +39,7 @@ static void power_supply_changed_work(struct work_struct *work)
struct power_supply *psy = container_of(work, struct power_supply,
changed_work);
- dev_dbg(psy->dev, "%s\n", __FUNCTION__);
+ dev_dbg(psy->dev, "%s\n", __func__);
class_for_each_device(power_supply_class, psy,
__power_supply_changed_work);
@@ -51,7 +51,7 @@ static void power_supply_changed_work(struct work_struct *work)
void power_supply_changed(struct power_supply *psy)
{
- dev_dbg(psy->dev, "%s\n", __FUNCTION__);
+ dev_dbg(psy->dev, "%s\n", __func__);
schedule_work(&psy->changed_work);
}
@@ -82,7 +82,7 @@ int power_supply_am_i_supplied(struct power_supply *psy)
error = class_for_each_device(power_supply_class, psy,
__power_supply_am_i_supplied);
- dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error);
+ dev_dbg(psy->dev, "%s %d\n", __func__, error);
return error;
}
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
index fa3034f85c38..2dece40c544f 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/power_supply_leds.c
@@ -24,7 +24,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
return;
- dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
+ dev_dbg(psy->dev, "%s %d\n", __func__, status.intval);
switch (status.intval) {
case POWER_SUPPLY_STATUS_FULL:
@@ -101,7 +101,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy)
if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
return;
- dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
+ dev_dbg(psy->dev, "%s %d\n", __func__, online.intval);
if (online.intval)
led_trigger_event(psy->online_trig, LED_FULL);
diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c
index 6c9592ce4996..85edf945ab86 100644
--- a/drivers/ps3/ps3-lpm.c
+++ b/drivers/ps3/ps3-lpm.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
+#include <asm/time.h>
#include <asm/ps3.h>
#include <asm/lv1call.h>
#include <asm/cell-pmu.h>
diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c
index 7605453b74fd..f17513dd9d4b 100644
--- a/drivers/ps3/ps3-sys-manager.c
+++ b/drivers/ps3/ps3-sys-manager.c
@@ -184,10 +184,7 @@ enum ps3_sys_manager_next_op {
/**
* 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_DEFAULT: Disk insert, power button, eject button.
* @PS3_SM_WAKE_W_O_L: Ether or wireless LAN.
* @PS3_SM_WAKE_P_O_R: Power on reset.
*
@@ -200,8 +197,6 @@ enum ps3_sys_manager_next_op {
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_W_O_L = 0x00000400,
PS3_SM_WAKE_P_O_R = 0x80000000,
};
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index 4142115d298e..c32822ad84a4 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -1,14 +1,6 @@
#
# RapidIO configuration
#
-config RAPIDIO_8_BIT_TRANSPORT
- bool "8-bit transport addressing"
- depends on RAPIDIO
- ---help---
- By default, the kernel assumes a 16-bit addressed RapidIO
- network. By selecting this option, the kernel will support
- an 8-bit addressed network.
-
config RAPIDIO_DISC_TIMEOUT
int "Discovery timeout duration (seconds)"
depends on RAPIDIO
diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c
index 8b56bbdd011e..a3824baca2e5 100644
--- a/drivers/rapidio/rio-access.c
+++ b/drivers/rapidio/rio-access.c
@@ -48,7 +48,7 @@ int __rio_local_read_config_##size \
u32 data = 0; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
- res = mport->ops->lcread(mport->id, offset, len, &data); \
+ res = mport->ops->lcread(mport, mport->id, offset, len, &data); \
*value = (type)data; \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
@@ -71,7 +71,7 @@ int __rio_local_write_config_##size \
unsigned long flags; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
- res = mport->ops->lcwrite(mport->id, offset, len, value); \
+ res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
}
@@ -108,7 +108,7 @@ int rio_mport_read_config_##size \
u32 data = 0; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
- res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \
+ res = mport->ops->cread(mport, mport->id, destid, hopcount, offset, len, &data); \
*value = (type)data; \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
@@ -131,7 +131,7 @@ int rio_mport_write_config_##size \
unsigned long flags; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
- res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \
+ res = mport->ops->cwrite(mport, mport->id, destid, hopcount, offset, len, value); \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
}
@@ -166,7 +166,7 @@ int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
unsigned long flags;
spin_lock_irqsave(&rio_doorbell_lock, flags);
- res = mport->ops->dsend(mport->id, destid, data);
+ res = mport->ops->dsend(mport, mport->id, destid, data);
spin_unlock_irqrestore(&rio_doorbell_lock, flags);
return res;
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 44420723a359..a926c896475e 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -73,7 +73,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount)
rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result);
- return RIO_GET_DID(result);
+ return RIO_GET_DID(port->sys_size, result);
}
/**
@@ -88,7 +88,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount)
static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)
{
rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR,
- RIO_SET_DID(did));
+ RIO_SET_DID(port->sys_size, did));
}
/**
@@ -100,7 +100,8 @@ static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u
*/
static void rio_local_set_device_id(struct rio_mport *port, u16 did)
{
- rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(did));
+ rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size,
+ did));
}
/**
@@ -350,8 +351,18 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rswitch->switchid = next_switchid;
rswitch->hopcount = hopcount;
rswitch->destid = destid;
+ rswitch->route_table = kzalloc(sizeof(u8)*
+ RIO_MAX_ROUTE_ENTRIES(port->sys_size),
+ GFP_KERNEL);
+ if (!rswitch->route_table) {
+ kfree(rdev);
+ rdev = NULL;
+ kfree(rswitch);
+ goto out;
+ }
/* Initialize switch route table */
- for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++)
+ for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size);
+ rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
rdev->rswitch = rswitch;
sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id,
@@ -480,7 +491,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
{
u32 result;
- rio_mport_read_config_32(port, RIO_ANY_DESTID, hopcount,
+ rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount,
RIO_HOST_DID_LOCK_CSR, &result);
return (u16) (result & 0xffff);
@@ -571,14 +582,16 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
}
/* Attempt to acquire device lock */
- rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount,
+ rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size),
+ hopcount,
RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
while ((tmp = rio_get_host_deviceid_lock(port, hopcount))
< port->host_deviceid) {
/* Delay a bit */
mdelay(1);
/* Attempt to acquire device lock again */
- rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount,
+ rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size),
+ hopcount,
RIO_HOST_DID_LOCK_CSR,
port->host_deviceid);
}
@@ -590,7 +603,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
}
/* Setup new RIO device */
- if ((rdev = rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) {
+ rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size),
+ hopcount, 1);
+ if (rdev) {
/* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices);
} else
@@ -598,7 +613,8 @@ 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);
+ sw_inport = rio_get_swpinfo_inport(port,
+ RIO_ANY_DESTID(port->sys_size), 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;
@@ -612,7 +628,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
}
num_ports =
- rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount);
+ rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size),
+ hopcount);
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
rio_name(rdev), rdev->vid, rdev->did, num_ports);
@@ -624,13 +641,15 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
cur_destid = next_destid;
if (rio_sport_is_active
- (port, RIO_ANY_DESTID, hopcount, port_num)) {
+ (port, RIO_ANY_DESTID(port->sys_size), hopcount,
+ port_num)) {
pr_debug(
"RIO: scanning device on port %d\n",
port_num);
rio_route_add_entry(port, rdev->rswitch,
- RIO_GLOBAL_TABLE,
- RIO_ANY_DESTID, port_num);
+ RIO_GLOBAL_TABLE,
+ RIO_ANY_DESTID(port->sys_size),
+ port_num);
if (rio_enum_peer(net, port, hopcount + 1) < 0)
return -1;
@@ -735,7 +754,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
pr_debug(
"RIO: scanning device on port %d\n",
port_num);
- for (ndestid = 0; ndestid < RIO_ANY_DESTID;
+ for (ndestid = 0;
+ ndestid < RIO_ANY_DESTID(port->sys_size);
ndestid++) {
rio_route_get_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE,
@@ -917,7 +937,9 @@ static void rio_build_route_tables(void)
list_for_each_entry(rdev, &rio_devices, global_list)
if (rio_is_switch(rdev))
- for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
+ for (i = 0;
+ i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
+ i++) {
if (rio_route_get_entry
(rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
i, &sport) < 0)
@@ -981,7 +1003,8 @@ int rio_disc_mport(struct rio_mport *mport)
del_timer_sync(&rio_enum_timer);
pr_debug("done\n");
- if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) {
+ if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
+ 0) < 0) {
printk(KERN_INFO
"RIO: master port %d device has failed discovery\n",
mport->id);
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 659e31164cf0..97a147f050d6 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -43,7 +43,8 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
if (!rdev->rswitch)
goto out;
- for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
+ for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
+ i++) {
if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
continue;
str +=
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 80c5f1ba2e49..680661abbc4b 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -43,7 +43,7 @@ u16 rio_local_get_device_id(struct rio_mport *port)
rio_local_read_config_32(port, RIO_DID_CSR, &result);
- return (RIO_GET_DID(result));
+ return (RIO_GET_DID(port->sys_size, result));
}
/**
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index 80e3f03b5041..7786d02581f2 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -51,10 +51,5 @@ extern struct rio_route_ops __end_rio_route_ops[];
DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \
vid, did, add_hook, get_hook)
-#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT
-#define RIO_GET_DID(x) ((x & 0x00ff0000) >> 16)
-#define RIO_SET_DID(x) ((x & 0x000000ff) << 16)
-#else
-#define RIO_GET_DID(x) (x & 0xffff)
-#define RIO_SET_DID(x) (x & 0xffff)
-#endif
+#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
+#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 4f28045d9ef2..8624f55d0560 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -419,7 +419,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
- if (unlikely(IS_ERR(rtc))) {
+ if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc->rtc_dev);
goto err;
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index dcdc142a3441..d060a06ce05b 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -854,11 +854,12 @@ cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
* don't define the IRQ. It should always be safe to
* hardcode it in these cases
*/
- return cmos_do_probe(&pnp->dev, &pnp->res.port_resource[0], 8);
+ return cmos_do_probe(&pnp->dev,
+ pnp_get_resource(pnp, IORESOURCE_IO, 0), 8);
else
return cmos_do_probe(&pnp->dev,
- &pnp->res.port_resource[0],
- pnp->res.irq_resource[0].start);
+ pnp_get_resource(pnp, IORESOURCE_IO, 0),
+ pnp_irq(pnp, 0));
}
static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index f389a28720d2..bbf97e65202a 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -99,45 +99,38 @@ struct ds1307 {
};
struct chip_desc {
- char name[9];
unsigned nvram56:1;
unsigned alarm:1;
- enum ds_type type;
};
-static const struct chip_desc chips[] = { {
- .name = "ds1307",
- .type = ds_1307,
+static const struct chip_desc chips[] = {
+[ds_1307] = {
.nvram56 = 1,
-}, {
- .name = "ds1337",
- .type = ds_1337,
+},
+[ds_1337] = {
.alarm = 1,
-}, {
- .name = "ds1338",
- .type = ds_1338,
+},
+[ds_1338] = {
.nvram56 = 1,
-}, {
- .name = "ds1339",
- .type = ds_1339,
+},
+[ds_1339] = {
.alarm = 1,
-}, {
- .name = "ds1340",
- .type = ds_1340,
-}, {
- .name = "m41t00",
- .type = m41t00,
+},
+[ds_1340] = {
+},
+[m41t00] = {
}, };
-static inline const struct chip_desc *find_chip(const char *s)
-{
- unsigned i;
-
- for (i = 0; i < ARRAY_SIZE(chips); i++)
- if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0)
- return &chips[i];
- return NULL;
-}
+static const struct i2c_device_id ds1307_id[] = {
+ { "ds1307", ds_1307 },
+ { "ds1337", ds_1337 },
+ { "ds1338", ds_1338 },
+ { "ds1339", ds_1339 },
+ { "ds1340", ds_1340 },
+ { "m41t00", m41t00 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1307_id);
static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
@@ -326,21 +319,15 @@ static struct bin_attribute nvram = {
static struct i2c_driver ds1307_driver;
-static int __devinit ds1307_probe(struct i2c_client *client)
+static int __devinit ds1307_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds1307 *ds1307;
int err = -ENODEV;
int tmp;
- const struct chip_desc *chip;
+ const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- chip = find_chip(client->name);
- if (!chip) {
- dev_err(&client->dev, "unknown chip type '%s'\n",
- client->name);
- return -ENODEV;
- }
-
if (!i2c_check_functionality(adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
@@ -361,7 +348,7 @@ static int __devinit ds1307_probe(struct i2c_client *client)
ds1307->msg[1].len = sizeof(ds1307->regs);
ds1307->msg[1].buf = ds1307->regs;
- ds1307->type = chip->type;
+ ds1307->type = id->driver_data;
switch (ds1307->type) {
case ds_1337:
@@ -550,6 +537,7 @@ static struct i2c_driver ds1307_driver = {
},
.probe = ds1307_probe,
.remove = __devexit_p(ds1307_remove),
+ .id_table = ds1307_id,
};
static int __init ds1307_init(void)
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 45bda186befc..fa2d2f8b3f4d 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -41,6 +41,12 @@
#define DS1374_REG_SR_AF 0x01 /* Alarm Flag */
#define DS1374_REG_TCR 0x09 /* Trickle Charge */
+static const struct i2c_device_id ds1374_id[] = {
+ { "rtc-ds1374", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1374_id);
+
struct ds1374 {
struct i2c_client *client;
struct rtc_device *rtc;
@@ -355,7 +361,8 @@ static const struct rtc_class_ops ds1374_rtc_ops = {
.ioctl = ds1374_ioctl,
};
-static int ds1374_probe(struct i2c_client *client)
+static int ds1374_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds1374 *ds1374;
int ret;
@@ -429,6 +436,7 @@ static struct i2c_driver ds1374_driver = {
},
.probe = ds1374_probe,
.remove = __devexit_p(ds1374_remove),
+ .id_table = ds1374_id,
};
static int __init ds1374_init(void)
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index a83a40b3ebaa..0f0d27d1c4ca 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -184,7 +184,7 @@ ds1511_wdog_disable(void)
static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
{
u8 mon, day, dow, hrs, min, sec, yrs, cen;
- unsigned int flags;
+ unsigned long flags;
/*
* won't have to change this for a while
@@ -247,7 +247,7 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
{
unsigned int century;
- unsigned int flags;
+ unsigned long flags;
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index fb15e3fb4ce2..fbb90b1e4098 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -490,7 +490,7 @@ isl1208_sysfs_unregister(struct device *dev)
}
static int
-isl1208_probe(struct i2c_client *client)
+isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int rc = 0;
struct rtc_device *rtc;
@@ -545,12 +545,19 @@ isl1208_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id isl1208_id[] = {
+ { "isl1208", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, isl1208_id);
+
static struct i2c_driver isl1208_driver = {
.driver = {
.name = "rtc-isl1208",
},
.probe = isl1208_probe,
.remove = isl1208_remove,
+ .id_table = isl1208_id,
};
static int __init
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index ba795a4db1e9..9f996ec881ce 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -51,7 +51,7 @@ EXPORT_SYMBOL(rtc_year_days);
*/
void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
{
- register int days, month, year;
+ unsigned int days, month, year;
days = time / 86400;
time -= days * 86400;
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 1cb33cac1237..a3e0880b38fb 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/i2c.h>
@@ -60,48 +61,21 @@
#define DRV_VERSION "0.05"
-struct m41t80_chip_info {
- const char *name;
- u8 features;
-};
-
-static const struct m41t80_chip_info m41t80_chip_info_tbl[] = {
- {
- .name = "m41t80",
- .features = 0,
- },
- {
- .name = "m41t81",
- .features = M41T80_FEATURE_HT,
- },
- {
- .name = "m41t81s",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41t82",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41t83",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41st84",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41st85",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41st87",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
+static const struct i2c_device_id m41t80_id[] = {
+ { "m41t80", 0 },
+ { "m41t81", M41T80_FEATURE_HT },
+ { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { }
};
+MODULE_DEVICE_TABLE(i2c, m41t80_id);
struct m41t80_data {
- const struct m41t80_chip_info *chip;
+ u8 features;
struct rtc_device *rtc;
};
@@ -208,7 +182,7 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
struct m41t80_data *clientdata = i2c_get_clientdata(client);
u8 reg;
- if (clientdata->chip->features & M41T80_FEATURE_BL) {
+ if (clientdata->features & M41T80_FEATURE_BL) {
reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
seq_printf(seq, "battery\t\t: %s\n",
(reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
@@ -756,12 +730,12 @@ static struct notifier_block wdt_notifier = {
*
*****************************************************************************
*/
-static int m41t80_probe(struct i2c_client *client)
+static int m41t80_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i, rc = 0;
+ int rc = 0;
struct rtc_device *rtc = NULL;
struct rtc_time tm;
- const struct m41t80_chip_info *chip;
struct m41t80_data *clientdata = NULL;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
@@ -773,19 +747,6 @@ static int m41t80_probe(struct i2c_client *client)
dev_info(&client->dev,
"chip found, driver version " DRV_VERSION "\n");
- chip = NULL;
- for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) {
- if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) {
- chip = &m41t80_chip_info_tbl[i];
- break;
- }
- }
- if (!chip) {
- dev_err(&client->dev, "%s is not supported\n", client->name);
- rc = -ENODEV;
- goto exit;
- }
-
clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
if (!clientdata) {
rc = -ENOMEM;
@@ -801,7 +762,7 @@ static int m41t80_probe(struct i2c_client *client)
}
clientdata->rtc = rtc;
- clientdata->chip = chip;
+ clientdata->features = id->driver_data;
i2c_set_clientdata(client, clientdata);
/* Make sure HT (Halt Update) bit is cleared */
@@ -810,7 +771,7 @@ static int m41t80_probe(struct i2c_client *client)
goto ht_err;
if (rc & M41T80_ALHOUR_HT) {
- if (chip->features & M41T80_FEATURE_HT) {
+ if (clientdata->features & M41T80_FEATURE_HT) {
m41t80_get_datetime(client, &tm);
dev_info(&client->dev, "HT bit was set!\n");
dev_info(&client->dev,
@@ -842,7 +803,8 @@ static int m41t80_probe(struct i2c_client *client)
goto exit;
#ifdef CONFIG_RTC_DRV_M41T80_WDT
- if (chip->features & M41T80_FEATURE_HT) {
+ if (clientdata->features & M41T80_FEATURE_HT) {
+ save_client = client;
rc = misc_register(&wdt_dev);
if (rc)
goto exit;
@@ -851,7 +813,6 @@ static int m41t80_probe(struct i2c_client *client)
misc_deregister(&wdt_dev);
goto exit;
}
- save_client = client;
}
#endif
return 0;
@@ -878,7 +839,7 @@ static int m41t80_remove(struct i2c_client *client)
struct rtc_device *rtc = clientdata->rtc;
#ifdef CONFIG_RTC_DRV_M41T80_WDT
- if (clientdata->chip->features & M41T80_FEATURE_HT) {
+ if (clientdata->features & M41T80_FEATURE_HT) {
misc_deregister(&wdt_dev);
unregister_reboot_notifier(&wdt_notifier);
}
@@ -896,6 +857,7 @@ static struct i2c_driver m41t80_driver = {
},
.probe = m41t80_probe,
.remove = m41t80_remove,
+ .id_table = m41t80_id,
};
static int __init m41t80_rtc_init(void)
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index a41681d26eba..0fc4c3630780 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -246,7 +246,8 @@ static const struct rtc_class_ops pcf8563_rtc_ops = {
.set_time = pcf8563_rtc_set_time,
};
-static int pcf8563_probe(struct i2c_client *client)
+static int pcf8563_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct pcf8563 *pcf8563;
@@ -299,12 +300,19 @@ static int pcf8563_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id pcf8563_id[] = {
+ { "pcf8563", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf8563_id);
+
static struct i2c_driver pcf8563_driver = {
.driver = {
.name = "rtc-pcf8563",
},
.probe = pcf8563_probe,
.remove = pcf8563_remove,
+ .id_table = pcf8563_id,
};
static int __init pcf8563_init(void)
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index 8d300e6d0d9e..0c6257a034ff 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -108,12 +108,10 @@ void rtc_proc_add_device(struct rtc_device *rtc)
if (rtc->id == 0) {
struct proc_dir_entry *ent;
- ent = create_proc_entry("driver/rtc", 0, NULL);
- if (ent) {
- ent->proc_fops = &rtc_proc_fops;
+ ent = proc_create_data("driver/rtc", 0, NULL,
+ &rtc_proc_fops, rtc);
+ if (ent)
ent->owner = rtc->owner;
- ent->data = rtc;
- }
}
}
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 7e63074708eb..56caf6b2c3e5 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -69,6 +69,15 @@ enum rtc_type {
rtc_rv5c387a,
};
+static const struct i2c_device_id rs5c372_id[] = {
+ { "rs5c372a", rtc_rs5c372a },
+ { "rs5c372b", rtc_rs5c372b },
+ { "rv5c386", rtc_rv5c386 },
+ { "rv5c387a", rtc_rv5c387a },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rs5c372_id);
+
/* REVISIT: this assumes that:
* - we're in the 21st century, so it's safe to ignore the century
* bit for rv5c38[67] (REG_MONTH bit 7);
@@ -494,7 +503,8 @@ static void rs5c_sysfs_unregister(struct device *dev)
static struct i2c_driver rs5c372_driver;
-static int rs5c372_probe(struct i2c_client *client)
+static int rs5c372_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
struct rs5c372 *rs5c372;
@@ -514,6 +524,7 @@ static int rs5c372_probe(struct i2c_client *client)
rs5c372->client = client;
i2c_set_clientdata(client, rs5c372);
+ rs5c372->type = id->driver_data;
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
rs5c372->regs = &rs5c372->buf[1];
@@ -522,19 +533,6 @@ static int rs5c372_probe(struct i2c_client *client)
if (err < 0)
goto exit_kfree;
- if (strcmp(client->name, "rs5c372a") == 0)
- rs5c372->type = rtc_rs5c372a;
- else if (strcmp(client->name, "rs5c372b") == 0)
- rs5c372->type = rtc_rs5c372b;
- else if (strcmp(client->name, "rv5c386") == 0)
- rs5c372->type = rtc_rv5c386;
- else if (strcmp(client->name, "rv5c387a") == 0)
- rs5c372->type = rtc_rv5c387a;
- else {
- rs5c372->type = rtc_rs5c372b;
- dev_warn(&client->dev, "assuming rs5c372b\n");
- }
-
/* clock may be set for am/pm or 24 hr time */
switch (rs5c372->type) {
case rtc_rs5c372a:
@@ -651,6 +649,7 @@ static struct i2c_driver rs5c372_driver = {
},
.probe = rs5c372_probe,
.remove = rs5c372_remove,
+ .id_table = rs5c372_id,
};
static __init int rs5c372_init(void)
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index e8abc90c32c5..a6fa1f2f2ca6 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -34,6 +34,12 @@
#define S35390A_FLAG_RESET 0x80
#define S35390A_FLAG_TEST 0x01
+static const struct i2c_device_id s35390a_id[] = {
+ { "s35390a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, s35390a_id);
+
struct s35390a {
struct i2c_client *client[8];
struct rtc_device *rtc;
@@ -195,7 +201,8 @@ static const struct rtc_class_ops s35390a_rtc_ops = {
static struct i2c_driver s35390a_driver;
-static int s35390a_probe(struct i2c_client *client)
+static int s35390a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err;
unsigned int i;
@@ -220,7 +227,7 @@ static int s35390a_probe(struct i2c_client *client)
/* This chip uses multiple addresses, use dummy devices for them */
for (i = 1; i < 8; ++i) {
s35390a->client[i] = i2c_new_dummy(client->adapter,
- client->addr + i, "rtc-s35390a");
+ client->addr + i);
if (!s35390a->client[i]) {
dev_err(&client->dev, "Address %02x unavailable\n",
client->addr + i);
@@ -296,6 +303,7 @@ static struct i2c_driver s35390a_driver = {
},
.probe = s35390a_probe,
.remove = s35390a_remove,
+ .id_table = s35390a_id,
};
static int __init s35390a_rtc_init(void)
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 110699bb4787..1f88e9e914ec 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -616,7 +616,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
goto err_badres;
}
- rtc->regbase = (void __iomem *)rtc->res->start;
+ rtc->regbase = ioremap_nocache(rtc->res->start, rtc->regsize);
if (unlikely(!rtc->regbase)) {
ret = -EINVAL;
goto err_badmap;
@@ -626,7 +626,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
&sh_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc_dev)) {
ret = PTR_ERR(rtc->rtc_dev);
- goto err_badmap;
+ goto err_unmap;
}
rtc->capabilities = RTC_DEF_CAPABILITIES;
@@ -653,7 +653,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"request period IRQ failed with %d, IRQ %d\n", ret,
rtc->periodic_irq);
- goto err_badmap;
+ goto err_unmap;
}
ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED,
@@ -663,7 +663,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
"request carry IRQ failed with %d, IRQ %d\n", ret,
rtc->carry_irq);
free_irq(rtc->periodic_irq, rtc);
- goto err_badmap;
+ goto err_unmap;
}
ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED,
@@ -674,7 +674,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
rtc->alarm_irq);
free_irq(rtc->carry_irq, rtc);
free_irq(rtc->periodic_irq, rtc);
- goto err_badmap;
+ goto err_unmap;
}
tmp = readb(rtc->regbase + RCR1);
@@ -684,6 +684,8 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
return 0;
+err_unmap:
+ iounmap(rtc->regbase);
err_badmap:
release_resource(rtc->res);
err_badres:
@@ -708,6 +710,8 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev)
release_resource(rtc->res);
+ iounmap(rtc->regbase);
+
platform_set_drvdata(pdev, NULL);
kfree(rtc);
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 095282f63523..eaf55945f21b 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -494,7 +494,8 @@ static void x1205_sysfs_unregister(struct device *dev)
}
-static int x1205_probe(struct i2c_client *client)
+static int x1205_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
unsigned char sr;
@@ -552,12 +553,19 @@ static int x1205_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id x1205_id[] = {
+ { "x1205", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, x1205_id);
+
static struct i2c_driver x1205_driver = {
.driver = {
.name = "rtc-x1205",
},
.probe = x1205_probe,
.remove = x1205_remove,
+ .id_table = x1205_id,
};
static int __init x1205_init(void)
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index ac6d4d3218b3..8ba3f135da22 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -925,6 +925,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
struct dasd_ccw_req *cqr;
struct dasd_device *device;
+ if (!intparm)
+ return;
cqr = (struct dasd_ccw_req *) intparm;
if (cqr->status != DASD_CQR_IN_IO) {
MESSAGE(KERN_DEBUG,
@@ -976,17 +978,16 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
if (IS_ERR(irb)) {
switch (PTR_ERR(irb)) {
case -EIO:
- dasd_handle_killed_request(cdev, intparm);
break;
case -ETIMEDOUT:
printk(KERN_WARNING"%s(%s): request timed out\n",
__func__, cdev->dev.bus_id);
- //FIXME - dasd uses own timeout interface...
break;
default:
printk(KERN_WARNING"%s(%s): unknown error %ld\n",
__func__, cdev->dev.bus_id, PTR_ERR(irb));
}
+ dasd_handle_killed_request(cdev, intparm);
return;
}
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index f4fb40257348..d774e79476fe 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -86,10 +86,10 @@ static DEFINE_SPINLOCK(dasd_devmap_lock);
static struct list_head dasd_hashlists[256];
int dasd_max_devindex;
-static struct dasd_devmap *dasd_add_busid(char *, int);
+static struct dasd_devmap *dasd_add_busid(const char *, int);
static inline int
-dasd_hash_busid(char *bus_id)
+dasd_hash_busid(const char *bus_id)
{
int hash, i;
@@ -394,7 +394,7 @@ dasd_parse(void)
* devices.
*/
static struct dasd_devmap *
-dasd_add_busid(char *bus_id, int features)
+dasd_add_busid(const char *bus_id, int features)
{
struct dasd_devmap *devmap, *new, *tmp;
int hash;
@@ -430,7 +430,7 @@ dasd_add_busid(char *bus_id, int features)
* Find devmap for device with given bus_id.
*/
static struct dasd_devmap *
-dasd_find_busid(char *bus_id)
+dasd_find_busid(const char *bus_id)
{
struct dasd_devmap *devmap, *tmp;
int hash;
@@ -452,7 +452,7 @@ dasd_find_busid(char *bus_id)
* Check if busid has been added to the list of dasd ranges.
*/
int
-dasd_busid_known(char *bus_id)
+dasd_busid_known(const char *bus_id)
{
return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
}
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 6c624bf44617..fb2f931cf844 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -598,7 +598,7 @@ struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
struct dasd_device *dasd_device_from_devindex(int);
int dasd_parse(void);
-int dasd_busid_known(char *);
+int dasd_busid_known(const char *);
/* externals in dasd_gendisk.c */
int dasd_gendisk_init(void);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 556063e8f7a9..03c0e40a92ff 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -157,6 +157,7 @@ static int dasd_devices_open(struct inode *inode, struct file *file)
}
static const struct file_operations dasd_devices_file_ops = {
+ .owner = THIS_MODULE,
.open = dasd_devices_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -311,17 +312,16 @@ out_error:
int
dasd_proc_init(void)
{
- dasd_proc_root_entry = proc_mkdir("dasd", &proc_root);
+ dasd_proc_root_entry = proc_mkdir("dasd", NULL);
if (!dasd_proc_root_entry)
goto out_nodasd;
dasd_proc_root_entry->owner = THIS_MODULE;
- dasd_devices_entry = create_proc_entry("devices",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
+ dasd_devices_entry = proc_create("devices",
+ S_IFREG | S_IRUGO | S_IWUSR,
+ dasd_proc_root_entry,
+ &dasd_devices_file_ops);
if (!dasd_devices_entry)
goto out_nodevices;
- dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
- dasd_devices_entry->owner = THIS_MODULE;
dasd_statistics_entry = create_proc_entry("statistics",
S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry);
@@ -335,7 +335,7 @@ dasd_proc_init(void)
out_nostatistics:
remove_proc_entry("devices", dasd_proc_root_entry);
out_nodevices:
- remove_proc_entry("dasd", &proc_root);
+ remove_proc_entry("dasd", NULL);
out_nodasd:
return -ENOENT;
}
@@ -345,5 +345,5 @@ dasd_proc_exit(void)
{
remove_proc_entry("devices", dasd_proc_root_entry);
remove_proc_entry("statistics", dasd_proc_root_entry);
- remove_proc_entry("dasd", &proc_root);
+ remove_proc_entry("dasd", NULL);
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 0e1f35c9ed9d..3e5653c92f4b 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -982,15 +982,16 @@ tty3215_write(struct tty_struct * tty,
/*
* Put character routine for 3215 ttys
*/
-static void
+static int
tty3215_put_char(struct tty_struct *tty, unsigned char ch)
{
struct raw3215_info *raw;
if (!tty)
- return;
+ return 0;
raw = (struct raw3215_info *) tty->driver_data;
raw3215_putchar(raw, ch);
+ return 1;
}
static void
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index b8f35bc52b7b..9e784d5f7f57 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -10,6 +10,7 @@
#include <linux/cpu.h>
#include <linux/sysdev.h>
#include <linux/workqueue.h>
+#include <asm/smp.h>
#include "sclp.h"
#define TAG "sclp_config: "
@@ -19,9 +20,11 @@ struct conf_mgm_data {
u8 ev_qualifier;
} __attribute__((packed));
+#define EV_QUAL_CPU_CHANGE 1
#define EV_QUAL_CAP_CHANGE 3
static struct work_struct sclp_cpu_capability_work;
+static struct work_struct sclp_cpu_change_work;
static void sclp_cpu_capability_notify(struct work_struct *work)
{
@@ -37,13 +40,24 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
put_online_cpus();
}
+static void sclp_cpu_change_notify(struct work_struct *work)
+{
+ smp_rescan_cpus();
+}
+
static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
{
struct conf_mgm_data *cdata;
cdata = (struct conf_mgm_data *)(evbuf + 1);
- if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE)
+ switch (cdata->ev_qualifier) {
+ case EV_QUAL_CPU_CHANGE:
+ schedule_work(&sclp_cpu_change_work);
+ break;
+ case EV_QUAL_CAP_CHANGE:
schedule_work(&sclp_cpu_capability_work);
+ break;
+ }
}
static struct sclp_register sclp_conf_register =
@@ -57,6 +71,7 @@ static int __init sclp_conf_init(void)
int rc;
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
+ INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
rc = sclp_register(&sclp_conf_register);
if (rc) {
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index e3b3d390b4a3..40b11521cd20 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -412,14 +412,14 @@ sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
* - including previous characters from sclp_tty_put_char() and strings from
* sclp_write() without final '\n' - will be written.
*/
-static void
+static int
sclp_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
sclp_tty_chars[sclp_tty_chars_count++] = ch;
if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
- }
+ } return 1;
}
/*
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index ed507594e62b..35707c04e613 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -524,11 +524,15 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp)
* NOTE: include/linux/tty_driver.h specifies that a character should be
* ignored if there is no room in the queue. This driver implements a different
* semantic in that it will block when there is no more room left.
+ *
+ * FIXME: putchar can currently be called from BH and other non blocking
+ * handlers so this semantic isn't a good idea.
*/
-static void
+static int
sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
{
__sclp_vt220_write(&ch, 1, 0, 0, 1);
+ return 1;
}
/*
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 7ad8cf157641..76e44eb7c47f 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -76,32 +76,9 @@ const char *tape_op_verbose[TO_SIZE] =
[TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC",
};
-static int
-busid_to_int(char *bus_id)
+static int devid_to_int(struct ccw_dev_id *dev_id)
{
- int dec;
- int d;
- char * s;
-
- for(s = bus_id, d = 0; *s != '\0' && *s != '.'; s++)
- d = (d * 10) + (*s - '0');
- dec = d;
- for(s++, d = 0; *s != '\0' && *s != '.'; s++)
- d = (d * 10) + (*s - '0');
- dec = (dec << 8) + d;
-
- for(s++; *s != '\0'; s++) {
- if (*s >= '0' && *s <= '9') {
- d = *s - '0';
- } else if (*s >= 'a' && *s <= 'f') {
- d = *s - 'a' + 10;
- } else {
- d = *s - 'A' + 10;
- }
- dec = (dec << 4) + d;
- }
-
- return dec;
+ return dev_id->devno + (dev_id->ssid << 16);
}
/*
@@ -551,6 +528,7 @@ tape_generic_probe(struct ccw_device *cdev)
{
struct tape_device *device;
int ret;
+ struct ccw_dev_id dev_id;
device = tape_alloc_device();
if (IS_ERR(device))
@@ -565,7 +543,8 @@ tape_generic_probe(struct ccw_device *cdev)
cdev->dev.driver_data = device;
cdev->handler = __tape_do_irq;
device->cdev = cdev;
- device->cdev_id = busid_to_int(cdev->dev.bus_id);
+ ccw_device_get_id(cdev, &dev_id);
+ device->cdev_id = devid_to_int(&dev_id);
PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
return ret;
}
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index c9b96d51b28f..e7c888c14e71 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -111,6 +111,7 @@ static int tape_proc_open(struct inode *inode, struct file *file)
static const struct file_operations tape_proc_ops =
{
+ .owner = THIS_MODULE,
.open = tape_proc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -124,14 +125,12 @@ void
tape_proc_init(void)
{
tape_proc_devices =
- create_proc_entry ("tapedevices", S_IFREG | S_IRUGO | S_IWUSR,
- &proc_root);
+ proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL,
+ &tape_proc_ops);
if (tape_proc_devices == NULL) {
PRINT_WARN("tape: Cannot register procfs entry tapedevices\n");
return;
}
- tape_proc_devices->proc_fops = &tape_proc_ops;
- tape_proc_devices->owner = THIS_MODULE;
}
/*
@@ -141,5 +140,5 @@ void
tape_proc_cleanup(void)
{
if (tape_proc_devices != NULL)
- remove_proc_entry ("tapedevices", &proc_root);
+ remove_proc_entry ("tapedevices", NULL);
}
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 70b1980a08b6..5043150019ac 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -965,8 +965,7 @@ tty3270_write_room(struct tty_struct *tty)
* Insert character into the screen at the current position with the
* current color and highlight. This function does NOT do cursor movement.
*/
-static void
-tty3270_put_character(struct tty3270 *tp, char ch)
+static void tty3270_put_character(struct tty3270 *tp, char ch)
{
struct tty3270_line *line;
struct tty3270_cell *cell;
@@ -1611,16 +1610,15 @@ tty3270_write(struct tty_struct * tty,
/*
* Put single characters to the ttys character buffer
*/
-static void
-tty3270_put_char(struct tty_struct *tty, unsigned char ch)
+static int tty3270_put_char(struct tty_struct *tty, unsigned char ch)
{
struct tty3270 *tp;
tp = tty->driver_data;
- if (!tp)
- return;
- if (tp->char_count < TTY3270_CHAR_BUF_SIZE)
- tp->char_buf[tp->char_count++] = ch;
+ if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
+ return 0;
+ tp->char_buf[tp->char_count++] = ch;
+ return 1;
}
/*
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index d364e0bfae12..e8487347e4d4 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -858,7 +858,7 @@ static int __init vmlogrdr_init(void)
for (i=0; i < MAXMINOR; ++i ) {
sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL);
if (!sys_ser[i].buffer) {
- rc = ENOMEM;
+ rc = -ENOMEM;
break;
}
sys_ser[i].current_position = sys_ser[i].buffer;
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index e8597ec92247..a4a5f2efea48 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -43,164 +43,169 @@ typedef enum {add, free} range_action;
* Function: blacklist_range
* (Un-)blacklist the devices from-to
*/
-static void
-blacklist_range (range_action action, unsigned int from, unsigned int to,
- unsigned int ssid)
+static int blacklist_range(range_action action, unsigned int from_ssid,
+ unsigned int to_ssid, unsigned int from,
+ unsigned int to, int msgtrigger)
{
- if (!to)
- to = from;
-
- if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
- printk (KERN_WARNING "cio: Invalid blacklist range "
- "0.%x.%04x to 0.%x.%04x, skipping\n",
- ssid, from, ssid, to);
- return;
+ if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
+ if (msgtrigger)
+ printk(KERN_WARNING "cio: Invalid cio_ignore range "
+ "0.%x.%04x-0.%x.%04x\n", from_ssid, from,
+ to_ssid, to);
+ return 1;
}
- for (; from <= to; from++) {
+
+ while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
+ (from <= to))) {
if (action == add)
- set_bit (from, bl_dev[ssid]);
+ set_bit(from, bl_dev[from_ssid]);
else
- clear_bit (from, bl_dev[ssid]);
+ clear_bit(from, bl_dev[from_ssid]);
+ from++;
+ if (from > __MAX_SUBCHANNEL) {
+ from_ssid++;
+ from = 0;
+ }
}
+
+ return 0;
}
-/*
- * Function: blacklist_busid
- * Get devno/busid from given string.
- * Shamelessly grabbed from dasd_devmap.c.
- */
-static int
-blacklist_busid(char **str, int *id0, int *ssid, int *devno)
+static int pure_hex(char **cp, unsigned int *val, int min_digit,
+ int max_digit, int max_val)
{
- int val, old_style;
- char *sav;
+ int diff;
+ unsigned int value;
- sav = *str;
+ diff = 0;
+ *val = 0;
- /* check for leading '0x' */
- old_style = 0;
- if ((*str)[0] == '0' && (*str)[1] == 'x') {
- *str += 2;
- old_style = 1;
- }
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- goto confused;
- val = simple_strtoul(*str, str, 16);
- if (old_style || (*str)[0] != '.') {
- *id0 = *ssid = 0;
- if (val < 0 || val > 0xffff)
- goto confused;
- *devno = val;
- if ((*str)[0] != ',' && (*str)[0] != '-' &&
- (*str)[0] != '\n' && (*str)[0] != '\0')
- goto confused;
- return 0;
+ while (isxdigit(**cp) && (diff <= max_digit)) {
+
+ if (isdigit(**cp))
+ value = **cp - '0';
+ else
+ value = tolower(**cp) - 'a' + 10;
+ *val = *val * 16 + value;
+ (*cp)++;
+ diff++;
}
- /* New style x.y.z busid */
- if (val < 0 || val > 0xff)
- goto confused;
- *id0 = val;
- (*str)++;
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- goto confused;
- val = simple_strtoul(*str, str, 16);
- if (val < 0 || val > 0xff || (*str)++[0] != '.')
- goto confused;
- *ssid = val;
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- goto confused;
- val = simple_strtoul(*str, str, 16);
- if (val < 0 || val > 0xffff)
- goto confused;
- *devno = val;
- if ((*str)[0] != ',' && (*str)[0] != '-' &&
- (*str)[0] != '\n' && (*str)[0] != '\0')
- goto confused;
+
+ if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
+ return 1;
+
return 0;
-confused:
- strsep(str, ",\n");
- printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
- return 1;
}
-static int
-blacklist_parse_parameters (char *str, range_action action)
+static int parse_busid(char *str, int *cssid, int *ssid, int *devno,
+ int msgtrigger)
{
- int from, to, from_id0, to_id0, from_ssid, to_ssid;
-
- while (*str != 0 && *str != '\n') {
- range_action ra = action;
- while(*str == ',')
- str++;
- if (*str == '!') {
- ra = !action;
- ++str;
+ char *str_work;
+ int val, rc, ret;
+
+ rc = 1;
+
+ if (*str == '\0')
+ goto out;
+
+ /* old style */
+ str_work = str;
+ val = simple_strtoul(str, &str_work, 16);
+
+ if (*str_work == '\0') {
+ if (val <= __MAX_SUBCHANNEL) {
+ *devno = val;
+ *ssid = 0;
+ *cssid = 0;
+ rc = 0;
}
+ goto out;
+ }
- /*
- * Since we have to parse the proc commands and the
- * kernel arguments we have to check four cases
- */
- if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
- strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
- int j;
-
- str += 3;
- for (j=0; j <= __MAX_SSID; j++)
- blacklist_range(ra, 0, __MAX_SUBCHANNEL, j);
- } else {
- int rc;
+ /* new style */
+ str_work = str;
+ ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
+ if (ret || (str_work[0] != '.'))
+ goto out;
+ str_work++;
+ ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
+ if (ret || (str_work[0] != '.'))
+ goto out;
+ str_work++;
+ ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
+ if (ret || (str_work[0] != '\0'))
+ goto out;
+
+ rc = 0;
+out:
+ if (rc && msgtrigger)
+ printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n",
+ str);
+
+ return rc;
+}
- rc = blacklist_busid(&str, &from_id0,
- &from_ssid, &from);
- if (rc)
- continue;
- to = from;
- to_id0 = from_id0;
- to_ssid = from_ssid;
- if (*str == '-') {
- str++;
- rc = blacklist_busid(&str, &to_id0,
- &to_ssid, &to);
- if (rc)
- continue;
- }
- if (*str == '-') {
- printk(KERN_WARNING "cio: invalid cio_ignore "
- "parameter '%s'\n",
- strsep(&str, ",\n"));
- continue;
- }
- if ((from_id0 != to_id0) ||
- (from_ssid != to_ssid)) {
- printk(KERN_WARNING "cio: invalid cio_ignore "
- "range %x.%x.%04x-%x.%x.%04x\n",
- from_id0, from_ssid, from,
- to_id0, to_ssid, to);
- continue;
+static int blacklist_parse_parameters(char *str, range_action action,
+ int msgtrigger)
+{
+ int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
+ int rc, totalrc;
+ char *parm;
+ range_action ra;
+
+ totalrc = 0;
+
+ while ((parm = strsep(&str, ","))) {
+ rc = 0;
+ ra = action;
+ if (*parm == '!') {
+ if (ra == add)
+ ra = free;
+ else
+ ra = add;
+ parm++;
+ }
+ if (strcmp(parm, "all") == 0) {
+ from_cssid = 0;
+ from_ssid = 0;
+ from = 0;
+ to_cssid = __MAX_CSSID;
+ to_ssid = __MAX_SSID;
+ to = __MAX_SUBCHANNEL;
+ } else {
+ rc = parse_busid(strsep(&parm, "-"), &from_cssid,
+ &from_ssid, &from, msgtrigger);
+ if (!rc) {
+ if (parm != NULL)
+ rc = parse_busid(parm, &to_cssid,
+ &to_ssid, &to,
+ msgtrigger);
+ else {
+ to_cssid = from_cssid;
+ to_ssid = from_ssid;
+ to = from;
+ }
}
- blacklist_range (ra, from, to, to_ssid);
}
+ if (!rc) {
+ rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
+ msgtrigger);
+ if (rc)
+ totalrc = 1;
+ } else
+ totalrc = 1;
}
- return 1;
+
+ return totalrc;
}
-/* Parsing the commandline for blacklist parameters, e.g. to blacklist
- * bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of:
- * - cio_ignore=1234-1236
- * - cio_ignore=0x1234-0x1235,1236
- * - cio_ignore=0x1234,1235-1236
- * - cio_ignore=1236 cio_ignore=1234-0x1236
- * - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
- * - cio_ignore=0.0.1234-0.0.1236
- * - cio_ignore=0.0.1234,0x1235,1236
- * - ...
- */
static int __init
blacklist_setup (char *str)
{
CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
- return blacklist_parse_parameters (str, add);
+ if (blacklist_parse_parameters(str, add, 1))
+ return 0;
+ return 1;
}
__setup ("cio_ignore=", blacklist_setup);
@@ -224,27 +229,23 @@ is_blacklisted (int ssid, int devno)
* Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore
*/
-static void
-blacklist_parse_proc_parameters (char *buf)
+static int blacklist_parse_proc_parameters(char *buf)
{
- if (strncmp (buf, "free ", 5) == 0) {
- blacklist_parse_parameters (buf + 5, free);
- } else if (strncmp (buf, "add ", 4) == 0) {
- /*
- * We don't need to check for known devices since
- * css_probe_device will handle this correctly.
- */
- blacklist_parse_parameters (buf + 4, add);
- } else {
- printk (KERN_WARNING "cio: cio_ignore: Parse error; \n"
- KERN_WARNING "try using 'free all|<devno-range>,"
- "<devno-range>,...'\n"
- KERN_WARNING "or 'add <devno-range>,"
- "<devno-range>,...'\n");
- return;
- }
+ int rc;
+ char *parm;
+
+ parm = strsep(&buf, " ");
+
+ if (strcmp("free", parm) == 0)
+ rc = blacklist_parse_parameters(buf, free, 0);
+ else if (strcmp("add", parm) == 0)
+ rc = blacklist_parse_parameters(buf, add, 0);
+ else
+ return 1;
css_schedule_reprobe();
+
+ return rc;
}
/* Iterator struct for all devices. */
@@ -328,6 +329,8 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
size_t user_len, loff_t *offset)
{
char *buf;
+ size_t i;
+ ssize_t rc, ret;
if (*offset)
return -EINVAL;
@@ -336,16 +339,27 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
buf = vmalloc (user_len + 1); /* maybe better use the stack? */
if (buf == NULL)
return -ENOMEM;
+ memset(buf, 0, user_len + 1);
+
if (strncpy_from_user (buf, user_buf, user_len) < 0) {
- vfree (buf);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out_free;
}
- buf[user_len] = '\0';
- blacklist_parse_proc_parameters (buf);
+ i = user_len - 1;
+ while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
+ buf[i] = '\0';
+ i--;
+ }
+ ret = blacklist_parse_proc_parameters(buf);
+ if (ret)
+ rc = -EINVAL;
+ else
+ rc = user_len;
+out_free:
vfree (buf);
- return user_len;
+ return rc;
}
static const struct seq_operations cio_ignore_proc_seq_ops = {
@@ -374,13 +388,10 @@ cio_ignore_proc_init (void)
{
struct proc_dir_entry *entry;
- entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
- &proc_root);
+ entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
+ &cio_ignore_proc_fops);
if (!entry)
return -ENOENT;
-
- entry->proc_fops = &cio_ignore_proc_fops;
-
return 0;
}
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index fe1ad1722158..26a930e832bd 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -152,44 +152,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
+static int __get_next_bus_id(const char **buf, char *bus_id)
+{
+ int rc, len;
+ char *start, *end;
+
+ start = (char *)*buf;
+ end = strchr(start, ',');
+ if (!end) {
+ /* Last entry. Strip trailing newline, if applicable. */
+ end = strchr(start, '\n');
+ if (end)
+ *end = '\0';
+ len = strlen(start) + 1;
+ } else {
+ len = end - start + 1;
+ end++;
+ }
+ if (len < BUS_ID_SIZE) {
+ strlcpy(bus_id, start, len);
+ rc = 0;
+ } else
+ rc = -EINVAL;
+ *buf = end;
+ return rc;
+}
+
+static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
+{
+ int cssid, ssid, devno;
+
+ /* Must be of form %x.%x.%04x */
+ if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
+ return 0;
+ return 1;
+}
+
/**
- * ccwgroup_create() - create and register a ccw group device
+ * ccwgroup_create_from_string() - create and register a ccw group device
* @root: parent device for the new device
* @creator_id: identifier of creating driver
* @cdrv: ccw driver of slave devices
- * @argc: number of slave devices
- * @argv: bus ids of slave devices
+ * @num_devices: number of slave devices
+ * @buf: buffer containing comma separated bus ids of slave devices
*
* Create and register a new ccw group device as a child of @root. Slave
- * devices are obtained from the list of bus ids given in @argv[] and must all
+ * devices are obtained from the list of bus ids given in @buf and must all
* belong to @cdrv.
* Returns:
* %0 on success and an error code on failure.
* Context:
* non-atomic
*/
-int ccwgroup_create(struct device *root, unsigned int creator_id,
- struct ccw_driver *cdrv, int argc, char *argv[])
+int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int num_devices,
+ const char *buf)
{
struct ccwgroup_device *gdev;
- int i;
- int rc;
+ int rc, i;
+ char tmp_bus_id[BUS_ID_SIZE];
+ const char *curr_buf;
- if (argc > 256) /* disallow dumb users */
- return -EINVAL;
-
- gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
+ gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
+ GFP_KERNEL);
if (!gdev)
return -ENOMEM;
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
- for (i = 0; i < argc; i++) {
- gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
-
- /* all devices have to be of the same type in
- * order to be grouped */
+ curr_buf = buf;
+ for (i = 0; i < num_devices && curr_buf; i++) {
+ rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
+ if (rc != 0)
+ goto error;
+ if (!__is_valid_bus_id(tmp_bus_id)) {
+ rc = -EINVAL;
+ goto error;
+ }
+ gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
+ /*
+ * All devices have to be of the same type in
+ * order to be grouped.
+ */
if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
@@ -203,9 +248,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
}
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
}
-
+ /* Check for sufficient number of bus ids. */
+ if (i < num_devices && !curr_buf) {
+ rc = -EINVAL;
+ goto error;
+ }
+ /* Check for trailing stuff. */
+ if (i == num_devices && strlen(curr_buf) > 0) {
+ rc = -EINVAL;
+ goto error;
+ }
gdev->creator_id = creator_id;
- gdev->count = argc;
+ gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = root;
gdev->dev.release = ccwgroup_release;
@@ -233,7 +287,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error:
- for (i = 0; i < argc; i++)
+ for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) {
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@@ -243,6 +297,7 @@ error:
put_device(&gdev->dev);
return rc;
}
+EXPORT_SYMBOL(ccwgroup_create_from_string);
static int __init
init_ccwgroup (void)
@@ -318,7 +373,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
{
struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
- unsigned int value;
+ unsigned long value;
int ret;
gdev = to_ccwgroupdev(dev);
@@ -329,7 +384,9 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
if (!try_module_get(gdrv->owner))
return -EINVAL;
- value = simple_strtoul(buf, NULL, 0);
+ ret = strict_strtoul(buf, 0, &value);
+ if (ret)
+ goto out;
ret = count;
if (value == 1)
ccwgroup_set_online(gdev);
@@ -337,6 +394,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
ccwgroup_set_offline(gdev);
else
ret = -EINVAL;
+out:
module_put(gdrv->owner);
return ret;
}
@@ -518,6 +576,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister);
-EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 23ffcc4768a7..82c6a2d45128 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -39,23 +39,6 @@ debug_info_t *cio_debug_msg_id;
debug_info_t *cio_debug_trace_id;
debug_info_t *cio_debug_crw_id;
-int cio_show_msg;
-
-static int __init
-cio_setup (char *parm)
-{
- if (!strcmp (parm, "yes"))
- cio_show_msg = 1;
- else if (!strcmp (parm, "no"))
- cio_show_msg = 0;
- else
- printk(KERN_ERR "cio: cio_setup: "
- "invalid cio_msg parameter '%s'", parm);
- return 1;
-}
-
-__setup ("cio_msg=", cio_setup);
-
/*
* Function: cio_debug_init
* Initializes three debug logs for common I/O:
@@ -166,7 +149,7 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
stsch (sch->schid, &sch->schib);
- CIO_MSG_EVENT(0, "cio_start: 'not oper' status for "
+ CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
"subchannel 0.%x.%04x!\n", sch->schid.ssid,
sch->schid.sch_no);
sprintf(dbf_text, "no%s", sch->dev.bus_id);
@@ -407,8 +390,7 @@ cio_modify (struct subchannel *sch)
/*
* Enable subchannel.
*/
-int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
- u32 intparm)
+int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
char dbf_txt[15];
int ccode;
@@ -426,7 +408,7 @@ int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
for (retry = 5, ret = 0; retry > 0; retry--) {
sch->schib.pmcw.ena = 1;
- sch->schib.pmcw.isc = isc;
+ sch->schib.pmcw.isc = sch->isc;
sch->schib.pmcw.intparm = intparm;
ret = cio_modify(sch);
if (ret == -ENODEV)
@@ -568,10 +550,9 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
* ... just being curious we check for non I/O subchannels
*/
if (sch->st != 0) {
- CIO_DEBUG(KERN_INFO, 0,
- "Subchannel 0.%x.%04x reports "
- "non-I/O subchannel type %04X\n",
- sch->schid.ssid, sch->schid.sch_no, sch->st);
+ CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports "
+ "non-I/O subchannel type %04X\n",
+ sch->schid.ssid, sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */
err = sch->st;
goto out;
@@ -589,7 +570,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(4, "Blacklisted device detected "
+ CIO_MSG_EVENT(6, "Blacklisted device detected "
"at devno %04X, subchannel set %x\n",
sch->schib.pmcw.dev, sch->schid.ssid);
err = -ENODEV;
@@ -600,23 +581,21 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
else
sch->opm = chp_get_sch_opm(sch);
sch->lpm = sch->schib.pmcw.pam & sch->opm;
+ sch->isc = 3;
- CIO_DEBUG(KERN_INFO, 0,
- "Detected device %04x on subchannel 0.%x.%04X"
- " - PIM = %02X, PAM = %02X, POM = %02X\n",
- sch->schib.pmcw.dev, sch->schid.ssid,
- sch->schid.sch_no, sch->schib.pmcw.pim,
- sch->schib.pmcw.pam, sch->schib.pmcw.pom);
+ CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X "
+ "- PIM = %02X, PAM = %02X, POM = %02X\n",
+ sch->schib.pmcw.dev, sch->schid.ssid,
+ sch->schid.sch_no, sch->schib.pmcw.pim,
+ sch->schib.pmcw.pam, sch->schib.pmcw.pom);
/*
* We now have to initially ...
- * ... set "interruption subclass"
* ... enable "concurrent sense"
* ... enable "multipath mode" if more than one
* CHPID is available. This is done regardless
* whether multiple paths are available for us.
*/
- sch->schib.pmcw.isc = 3; /* could be smth. else */
sch->schib.pmcw.csense = 1; /* concurrent sense */
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
@@ -812,6 +791,7 @@ cio_probe_console(void)
* enable console I/O-interrupt subclass 7
*/
ctl_set_bit(6, 24);
+ console_subchannel.isc = 7;
console_subchannel.schib.pmcw.isc = 7;
console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 08f2235c5a6f..6e933aebe013 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -74,6 +74,7 @@ struct subchannel {
__u8 lpm; /* logical path mask */
__u8 opm; /* operational path mask */
struct schib schib; /* subchannel information block */
+ int isc; /* desired interruption subclass */
struct chsc_ssd_info ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
struct css_driver *driver;
@@ -85,7 +86,7 @@ struct subchannel {
#define to_subchannel(n) container_of(n, struct subchannel, dev)
extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
-extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
+extern int cio_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
extern int cio_clear (struct subchannel *);
@@ -117,6 +118,4 @@ extern void *cio_get_console_priv(void);
#define cio_get_console_priv() NULL
#endif
-extern int cio_show_msg;
-
#endif
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index d7429ef6c666..e64e8278c42e 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -31,10 +31,4 @@ static inline void CIO_HEX_EVENT(int level, void *data, int length)
}
}
-#define CIO_DEBUG(printk_level, event_level, msg...) do { \
- if (cio_show_msg) \
- printk(printk_level "cio: " msg); \
- CIO_MSG_EVENT(event_level, msg); \
- } while (0)
-
#endif
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index f4c132ab39ed..2808b6833b9e 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1219,16 +1219,21 @@ static ssize_t cmb_enable_store(struct device *dev,
{
struct ccw_device *cdev;
int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 16, &val);
+ if (ret)
+ return ret;
cdev = to_ccwdev(dev);
- switch (buf[0]) {
- case '0':
+ switch (val) {
+ case 0:
ret = disable_cmf(cdev);
if (ret)
dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
break;
- case '1':
+ case 1:
ret = enable_cmf(cdev);
if (ret && ret != -EBUSY)
dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index c1afab5f72d6..a76956512b2d 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -570,7 +570,7 @@ static void reprobe_all(struct work_struct *unused)
{
int ret;
- CIO_MSG_EVENT(2, "reprobe start\n");
+ CIO_MSG_EVENT(4, "reprobe start\n");
need_reprobe = 0;
/* Make sure initial subchannel scan is done. */
@@ -578,7 +578,7 @@ static void reprobe_all(struct work_struct *unused)
atomic_read(&ccw_device_init_count) == 0);
ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
- CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+ CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
need_reprobe);
}
@@ -705,13 +705,17 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
{
struct channel_subsystem *css = to_css(dev);
int ret;
+ unsigned long val;
+ ret = strict_strtoul(buf, 16, &val);
+ if (ret)
+ return ret;
mutex_lock(&css->mutex);
- switch (buf[0]) {
- case '0':
+ switch (val) {
+ case 0:
ret = css->cm_enabled ? chsc_secm(css, 0) : 0;
break;
- case '1':
+ case 1:
ret = css->cm_enabled ? 0 : chsc_secm(css, 1);
break;
default:
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e0c7adb8958e..e22813db74a2 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -341,7 +341,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
rc = device_schedule_callback(&cdev->dev,
ccw_device_remove_orphan_cb);
if (rc)
- CIO_MSG_EVENT(2, "Couldn't unregister orphan "
+ CIO_MSG_EVENT(0, "Couldn't unregister orphan "
"0.%x.%04x\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -351,7 +351,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
rc = device_schedule_callback(cdev->dev.parent,
ccw_device_remove_sch_cb);
if (rc)
- CIO_MSG_EVENT(2, "Couldn't unregister disconnected device "
+ CIO_MSG_EVENT(0, "Couldn't unregister disconnected device "
"0.%x.%04x\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -397,7 +397,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -433,7 +433,7 @@ int ccw_device_set_online(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- CIO_MSG_EVENT(2, "ccw_device_online returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_online returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -451,7 +451,7 @@ int ccw_device_set_online(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else
- CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -512,8 +512,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ccw_device *cdev = to_ccwdev(dev);
- int i, force;
- char *tmp;
+ int force, ret;
+ unsigned long i;
if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
return -EAGAIN;
@@ -525,25 +525,30 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
if (!strncmp(buf, "force\n", count)) {
force = 1;
i = 1;
+ ret = 0;
} else {
force = 0;
- i = simple_strtoul(buf, &tmp, 16);
+ ret = strict_strtoul(buf, 16, &i);
}
-
+ if (ret)
+ goto out;
switch (i) {
case 0:
online_store_handle_offline(cdev);
+ ret = count;
break;
case 1:
online_store_handle_online(cdev, force);
+ ret = count;
break;
default:
- count = -EINVAL;
+ ret = -EINVAL;
}
+out:
if (cdev->drv)
module_put(cdev->drv->owner);
atomic_set(&cdev->private->onoff, 0);
- return count;
+ return ret;
}
static ssize_t
@@ -798,7 +803,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
other_sch = to_subchannel(get_device(cdev->dev.parent));
ret = device_move(&cdev->dev, &sch->dev);
if (ret) {
- CIO_MSG_EVENT(2, "Moving disconnected device 0.%x.%04x failed "
+ CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
"(ret=%d)!\n", cdev->private->dev_id.ssid,
cdev->private->dev_id.devno, ret);
put_device(&other_sch->dev);
@@ -928,7 +933,7 @@ io_subchannel_register(struct work_struct *work)
ret = device_reprobe(&cdev->dev);
if (ret)
/* We can't do much here. */
- CIO_MSG_EVENT(2, "device_reprobe() returned"
+ CIO_MSG_EVENT(0, "device_reprobe() returned"
" %d for 0.%x.%04x\n", ret,
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -1081,7 +1086,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
rc = device_move(&cdev->dev, &sch->dev);
mutex_unlock(&sch->reg_mutex);
if (rc) {
- CIO_MSG_EVENT(2, "Moving device 0.%x.%04x to subchannel "
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel "
"0.%x.%04x failed (ret=%d)!\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno, sch->schid.ssid,
@@ -1441,8 +1446,7 @@ ccw_device_remove (struct device *dev)
wait_event(cdev->private->wait_q,
dev_fsm_final_state(cdev));
else
- //FIXME: we can't fail!
- CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -1519,7 +1523,7 @@ static int recovery_check(struct device *dev, void *data)
spin_lock_irq(cdev->ccwlock);
switch (cdev->private->state) {
case DEV_STATE_DISCONNECTED:
- CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+ CIO_MSG_EVENT(4, "recovery: trigger 0.%x.%04x\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
dev_fsm_event(cdev, DEV_EVENT_VERIFY);
@@ -1549,7 +1553,7 @@ static void recovery_work_func(struct work_struct *unused)
}
spin_unlock_irq(&recovery_lock);
} else
- CIO_MSG_EVENT(2, "recovery: end\n");
+ CIO_MSG_EVENT(4, "recovery: end\n");
}
static DECLARE_WORK(recovery_work, recovery_work_func);
@@ -1567,7 +1571,7 @@ void ccw_device_schedule_recovery(void)
{
unsigned long flags;
- CIO_MSG_EVENT(2, "recovery: schedule\n");
+ CIO_MSG_EVENT(4, "recovery: schedule\n");
spin_lock_irqsave(&recovery_lock, flags);
if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
recovery_phase = 0;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 4b92c84fb438..e268d5a77c12 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -322,10 +322,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
same_dev = 0; /* Keep the compiler quiet... */
switch (state) {
case DEV_STATE_NOT_OPER:
- CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : unknown device %04x on subchannel "
- "0.%x.%04x\n", cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
+ CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
+ "subchannel 0.%x.%04x\n",
+ cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
break;
case DEV_STATE_OFFLINE:
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
@@ -348,20 +348,19 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
return;
}
/* Issue device info message. */
- CIO_DEBUG(KERN_INFO, 2,
- "SenseID : device 0.%x.%04x reports: "
- "CU Type/Mod = %04X/%02X, Dev Type/Mod = "
- "%04X/%02X\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno,
- cdev->id.cu_type, cdev->id.cu_model,
- cdev->id.dev_type, cdev->id.dev_model);
+ CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
+ "CU Type/Mod = %04X/%02X, Dev Type/Mod = "
+ "%04X/%02X\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno,
+ cdev->id.cu_type, cdev->id.cu_model,
+ cdev->id.dev_type, cdev->id.dev_model);
break;
case DEV_STATE_BOXED:
- CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : boxed device %04x on subchannel "
- "0.%x.%04x\n", cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
+ CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
+ " subchannel 0.%x.%04x\n",
+ cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
break;
}
cdev->private->state = state;
@@ -443,9 +442,8 @@ ccw_device_done(struct ccw_device *cdev, int state)
if (state == DEV_STATE_BOXED)
- CIO_DEBUG(KERN_WARNING, 2,
- "Boxed device %04x on subchannel %04x\n",
- cdev->private->dev_id.devno, sch->schid.sch_no);
+ CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
+ cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
@@ -555,8 +553,7 @@ ccw_device_recognition(struct ccw_device *cdev)
(cdev->private->state != DEV_STATE_BOXED))
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
- ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return ret;
@@ -667,8 +664,7 @@ ccw_device_online(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
if (css_init_done && !get_device(&cdev->dev))
return -ENODEV;
- ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret != 0) {
/* Couldn't enable the subchannel for i/o. Sick device. */
if (ret == -ENODEV)
@@ -902,7 +898,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
/* Basic sense hasn't started. Try again. */
ccw_device_do_sense(cdev, irb);
else {
- CIO_MSG_EVENT(2, "Huh? 0.%x.%04x: unsolicited "
+ CIO_MSG_EVENT(0, "0.%x.%04x: unsolicited "
"interrupt during w4sense...\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -1048,8 +1044,7 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
- if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch) != 0)
+ if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return;
@@ -1082,7 +1077,6 @@ device_trigger_reprobe(struct subchannel *sch)
*/
sch->lpm = sch->schib.pmcw.pam & sch->opm;
/* Re-set some bits in the pmcw that were lost. */
- sch->schib.pmcw.isc = 3;
sch->schib.pmcw.csense = 1;
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
@@ -1173,8 +1167,10 @@ ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event)
static void
ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event)
{
- CIO_MSG_EVENT(0, "dev_jumptable[%i][%i] == NULL\n",
- cdev->private->state, dev_event);
+ CIO_MSG_EVENT(0, "Internal state [%i][%i] not handled for device "
+ "0.%x.%04x\n", cdev->private->state, dev_event,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
BUG();
}
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index dc4d87f77f6c..cba7020517ed 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -214,7 +214,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
* sense id information. So, for intervention required,
* we use the "whack it until it talks" strategy...
*/
- CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel "
+ CIO_MSG_EVENT(0, "SenseID : device %04x on Subchannel "
"0.%x.%04x reports cmd reject\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no);
@@ -239,7 +239,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
lpm = to_io_private(sch)->orb.lpm;
if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
- CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
+ CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x "
"on subchannel 0.%x.%04x is "
"'not operational'\n", lpm,
cdev->private->dev_id.devno,
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index a1718a0aa539..f308ad55a6d5 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -508,7 +508,7 @@ ccw_device_stlck(struct ccw_device *cdev)
return -ENOMEM;
}
spin_lock_irqsave(sch->lock, flags);
- ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret)
goto out_unlock;
/*
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index c52449a1f9fc..5cf7be008e98 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -79,7 +79,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
/* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret != -EACCES)
return ret;
- CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
+ CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not "
"operational'\n",
cdev->private->dev_id.devno,
@@ -159,7 +159,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
u8 lpm;
lpm = to_io_private(sch)->orb.lpm;
- CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
+ CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, lpm);
@@ -243,16 +243,10 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
/* Setup sense path group id channel program. */
cdev->private->pgid[0].inf.fc = func;
ccw = cdev->private->iccws;
- if (!cdev->private->flags.pgid_single) {
- cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
- ccw->cmd_code = CCW_CMD_SUSPEND_RECONN;
- ccw->cda = 0;
- ccw->count = 0;
- ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ccw++;
- } else
+ if (cdev->private->flags.pgid_single)
cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
-
+ else
+ cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
ccw->cmd_code = CCW_CMD_SET_PGID;
ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
ccw->count = sizeof (struct pgid);
@@ -275,7 +269,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
return ret;
}
/* PGID command failed on this path. */
- CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
+ CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
@@ -317,7 +311,7 @@ static int __ccw_device_do_nop(struct ccw_device *cdev)
return ret;
}
/* nop command failed on this path. */
- CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
+ CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
@@ -362,7 +356,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
return -EAGAIN;
}
if (irb->scsw.cc == 3) {
- CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x,"
+ CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
@@ -391,7 +385,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev)
return -ETIME;
}
if (irb->scsw.cc == 3) {
- CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
+ CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 10aa1e780801..445cf364e461 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -3632,7 +3632,7 @@ qdio_add_procfs_entry(void)
{
proc_perf_file_registration=0;
qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
- S_IFREG|0444,&proc_root);
+ S_IFREG|0444,NULL);
if (qdio_perf_proc_file) {
qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read;
} else proc_perf_file_registration=-1;
@@ -3647,7 +3647,7 @@ static void
qdio_remove_procfs_entry(void)
{
if (!proc_perf_file_registration) /* means if it went ok earlier */
- remove_proc_entry(QDIO_PERF,&proc_root);
+ remove_proc_entry(QDIO_PERF,NULL);
}
/**
@@ -3663,11 +3663,11 @@ qdio_performance_stats_show(struct bus_type *bus, char *buf)
static ssize_t
qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
{
- char *tmp;
- int i;
+ unsigned long i;
+ int ret;
- i = simple_strtoul(buf, &tmp, 16);
- if ((i == 0) || (i == 1)) {
+ ret = strict_strtoul(buf, 16, &i);
+ if (!ret && ((i == 0) || (i == 1))) {
if (i == qdio_performance_stats)
return count;
qdio_performance_stats = i;
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index bbef3764fbf8..47a7e6200b26 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -17,6 +17,7 @@
#include <linux/virtio_config.h>
#include <linux/interrupt.h>
#include <linux/virtio_ring.h>
+#include <linux/pfn.h>
#include <asm/io.h>
#include <asm/kvm_para.h>
#include <asm/kvm_virtio.h>
@@ -180,11 +181,10 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
config = kvm_vq_config(kdev->desc)+index;
- if (add_shared_memory(config->address,
- vring_size(config->num, PAGE_SIZE))) {
- err = -ENOMEM;
+ err = vmem_add_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
+ if (err)
goto out;
- }
vq = vring_new_virtqueue(config->num, vdev, (void *) config->address,
kvm_notify, callback);
@@ -202,8 +202,8 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
vq->priv = config;
return vq;
unmap:
- remove_shared_memory(config->address, vring_size(config->num,
- PAGE_SIZE));
+ vmem_remove_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
out:
return ERR_PTR(err);
}
@@ -213,8 +213,8 @@ static void kvm_del_vq(struct virtqueue *vq)
struct kvm_vqconfig *config = vq->priv;
vring_del_virtqueue(vq);
- remove_shared_memory(config->address,
- vring_size(config->num, PAGE_SIZE));
+ vmem_remove_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
}
/*
@@ -318,12 +318,13 @@ static int __init kvm_devices_init(void)
return rc;
}
- if (add_shared_memory((max_pfn) << PAGE_SHIFT, PAGE_SIZE)) {
+ rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE);
+ if (rc) {
device_unregister(&kvm_root);
- return -ENOMEM;
+ return rc;
}
- kvm_devices = (void *) (max_pfn << PAGE_SHIFT);
+ kvm_devices = (void *) PFN_PHYS(max_pfn);
ctl_set_bit(0, 9);
register_external_interrupt(0x2603, kvm_extint_handler);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index 76728ae4b843..8e7697305a4c 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
{
- const char *start, *end;
- char bus_ids[2][BUS_ID_SIZE], *argv[2];
- int i;
int ret;
struct ccwgroup_driver *cdrv;
cdrv = to_ccwgroupdrv(drv);
if (!cdrv)
return -EINVAL;
- start = buf;
- for (i=0; i<2; i++) {
- static const char delim[] = {',', '\n'};
- int len;
-
- if (!(end = strchr(start, delim[i])))
- return -EINVAL;
- len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
- strlcpy (bus_ids[i], start, len);
- argv[i] = bus_ids[i];
- start = end + 1;
- }
-
- ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
- &cu3088_driver, 2, argv);
+ ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
+ &cu3088_driver, 2, buf);
return (ret == 0) ? count : ret;
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index f51ed9972587..dd22f4b37037 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1793,7 +1793,8 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len)
skb->protocol = card->lan_type_trans(skb, card->dev);
card->stats.rx_bytes += skb_len;
card->stats.rx_packets++;
- *((__u32 *)skb->cb) = ++card->pkt_seq;
+ if (skb->protocol == htons(ETH_P_802_2))
+ *((__u32 *)skb->cb) = ++card->pkt_seq;
netif_rx(skb);
}
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 8f876f6ab367..e4ba6a0372ac 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1313,8 +1313,6 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
* and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
- if (!in_atomic())
- fsm_event(privptr->fsm, DEV_EVENT_START, dev);
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
@@ -2147,6 +2145,7 @@ static int __init netiucv_init(void)
if (rc)
goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __func__);
+ netiucv_driver.groups = netiucv_drv_attr_groups;
rc = driver_register(&netiucv_driver);
if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 66f4f12503c9..699ac11debd8 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -72,22 +72,7 @@ struct qeth_dbf_info {
debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text)
#define QETH_DBF_TEXT_(name, level, text...) \
- do { \
- if (qeth_dbf_passes(qeth_dbf[QETH_DBF_##name].id, level)) { \
- char *dbf_txt_buf = \
- get_cpu_var(QETH_DBF_TXT_BUF); \
- sprintf(dbf_txt_buf, text); \
- debug_text_event(qeth_dbf[QETH_DBF_##name].id, \
- level, dbf_txt_buf); \
- put_cpu_var(QETH_DBF_TXT_BUF); \
- } \
- } while (0)
-
-/* Allow to sort out low debug levels early to avoid wasted sprints */
-static inline int qeth_dbf_passes(debug_info_t *dbf_grp, int level)
-{
- return (level <= dbf_grp->level);
-}
+ qeth_dbf_longtext(QETH_DBF_##name, level, text)
/**
* some more debug stuff
@@ -773,27 +758,6 @@ static inline int qeth_get_micros(void)
return (int) (get_clock() >> 12);
}
-static inline void *qeth_push_skb(struct qeth_card *card, struct sk_buff *skb,
- int size)
-{
- void *hdr;
-
- hdr = (void *) skb_push(skb, size);
- /*
- * sanity check, the Linux memory allocation scheme should
- * never present us cases like this one (the qdio header size plus
- * the first 40 bytes of the paket cross a 4k boundary)
- */
- if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
- (((unsigned long) hdr + size +
- QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
- PRINT_ERR("Misaligned packet on interface %s. Discarded.",
- QETH_CARD_IFNAME(card));
- return NULL;
- }
- return hdr;
-}
-
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
switch (skb->protocol) {
@@ -806,6 +770,12 @@ static inline int qeth_get_ip_version(struct sk_buff *skb)
}
}
+static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
+ struct qeth_buffer_pool_entry *entry)
+{
+ list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
+}
+
struct qeth_eddp_context;
extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
@@ -843,8 +813,6 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
int qeth_query_setadapterparms(struct qeth_card *);
int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int,
unsigned int, const char *);
-void qeth_put_buffer_pool_entry(struct qeth_card *,
- struct qeth_buffer_pool_entry *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct qdio_buffer *, struct qdio_buffer_element **, int *,
@@ -880,8 +848,6 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
void *reply_param);
int qeth_get_cast_type(struct qeth_card *, struct sk_buff *);
int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
-struct sk_buff *qeth_prepare_skb(struct qeth_card *, struct sk_buff *,
- struct qeth_hdr **);
int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int);
int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int,
@@ -894,6 +860,8 @@ void qeth_core_get_ethtool_stats(struct net_device *,
struct ethtool_stats *, u64 *);
void qeth_core_get_strings(struct net_device *, u32, u8 *);
void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
+int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 055f5c3e7b56..436bf1f6d4a6 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -26,9 +26,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
-static DEFINE_PER_CPU(char[256], qeth_core_dbf_txt_buf);
-#define QETH_DBF_TXT_BUF qeth_core_dbf_txt_buf
-
struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */
/* N P A M L V H */
@@ -2255,14 +2252,6 @@ void qeth_print_status_message(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_print_status_message);
-void qeth_put_buffer_pool_entry(struct qeth_card *card,
- struct qeth_buffer_pool_entry *entry)
-{
- QETH_DBF_TEXT(TRACE, 6, "ptbfplen");
- list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
-}
-EXPORT_SYMBOL_GPL(qeth_put_buffer_pool_entry);
-
static void qeth_initialize_working_pool_list(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@@ -2603,7 +2592,6 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
int rc;
int newcount = 0;
- QETH_DBF_TEXT(TRACE, 6, "queinbuf");
count = (index < queue->next_buf_to_init)?
card->qdio.in_buf_pool.buf_count -
(queue->next_buf_to_init - index) :
@@ -2792,8 +2780,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
int i;
unsigned int qdio_flags;
- QETH_DBF_TEXT(TRACE, 6, "flushbuf");
-
for (i = index; i < index + count; ++i) {
buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
buf->buffer->element[buf->next_element_to_fill - 1].flags |=
@@ -3037,49 +3023,6 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
-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 *qeth_realloc_headroom(struct qeth_card *card,
- struct sk_buff *skb, int size)
-{
- struct sk_buff *new_skb = skb;
-
- if (skb_headroom(skb) >= size)
- return skb;
- new_skb = skb_realloc_headroom(skb, size);
- if (!new_skb)
- PRINT_ERR("Could not realloc headroom for qeth_hdr "
- "on interface %s", QETH_CARD_IFNAME(card));
- return new_skb;
-}
-
-struct sk_buff *qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_hdr **hdr)
-{
- struct sk_buff *new_skb;
-
- QETH_DBF_TEXT(TRACE, 6, "prepskb");
-
- new_skb = qeth_realloc_headroom(card, skb,
- sizeof(struct qeth_hdr));
- if (!new_skb)
- return NULL;
-
- *hdr = ((struct qeth_hdr *)qeth_push_skb(card, new_skb,
- sizeof(struct qeth_hdr)));
- if (*hdr == NULL) {
- __qeth_free_new_skb(skb, new_skb);
- return NULL;
- }
- return new_skb;
-}
-EXPORT_SYMBOL_GPL(qeth_prepare_skb);
-
int qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@@ -3100,8 +3043,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
-static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
- int is_tso, int *next_element_to_fill)
+static inline void __qeth_fill_buffer(struct sk_buff *skb,
+ struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill)
{
int length = skb->len;
int length_here;
@@ -3143,15 +3086,13 @@ static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
*next_element_to_fill = element;
}
-static int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
+static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf, struct sk_buff *skb)
{
struct qdio_buffer *buffer;
struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0;
- QETH_DBF_TEXT(TRACE, 6, "qdfillbf");
-
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
@@ -3210,8 +3151,6 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
int flush_cnt = 0;
int index;
- QETH_DBF_TEXT(TRACE, 6, "dosndpfa");
-
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@@ -3263,8 +3202,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
int tmp;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 6, "dosndpkt");
-
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@@ -3827,27 +3764,8 @@ static struct ccw_driver qeth_ccw_driver = {
static int qeth_core_driver_group(const char *buf, struct device *root_dev,
unsigned long driver_id)
{
- const char *start, *end;
- char bus_ids[3][BUS_ID_SIZE], *argv[3];
- int i;
-
- start = buf;
- for (i = 0; i < 3; i++) {
- static const char delim[] = { ',', ',', '\n' };
- int len;
-
- end = strchr(start, delim[i]);
- if (!end)
- return -EINVAL;
- len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
- strncpy(bus_ids[i], start, len);
- bus_ids[i][len] = '\0';
- start = end + 1;
- argv[i] = bus_ids[i];
- }
-
- return (ccwgroup_create(root_dev, driver_id,
- &qeth_ccw_driver, 3, argv));
+ return ccwgroup_create_from_string(root_dev, driver_id,
+ &qeth_ccw_driver, 3, buf);
}
int qeth_core_hardsetup_card(struct qeth_card *card)
@@ -3885,8 +3803,9 @@ retry:
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
return rc;
}
-
- mpno = QETH_MAX_PORTNO;
+ mpno = qdio_get_ssqd_pct(CARD_DDEV(card));
+ if (mpno)
+ mpno = min(mpno - 1, QETH_MAX_PORTNO);
if (card->info.portno > mpno) {
PRINT_ERR("Device %s does not offer port number %d \n.",
CARD_BUS_ID(card), card->info.portno);
@@ -3980,7 +3899,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
int use_rx_sg = 0;
int frag = 0;
- QETH_DBF_TEXT(TRACE, 6, "nextskb");
/* qeth_hdr must not cross element boundaries */
if (element->length < offset + sizeof(struct qeth_hdr)) {
if (qeth_is_last_sbale(element))
@@ -4086,6 +4004,18 @@ static void qeth_unregister_dbf_views(void)
}
}
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...)
+{
+ char dbf_txt_buf[32];
+
+ if (level > (qeth_dbf[dbf_nix].id)->level)
+ return;
+ snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text);
+ debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
+
+}
+EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
+
static int qeth_register_dbf_views(void)
{
int ret;
@@ -4433,6 +4363,96 @@ void qeth_core_get_drvinfo(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo);
+int qeth_core_ethtool_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct qeth_card *card = netdev_priv(netdev);
+ enum qeth_link_types link_type;
+
+ if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan))
+ link_type = QETH_LINK_TYPE_10GBIT_ETH;
+ else
+ link_type = card->info.link_type;
+
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = SUPPORTED_Autoneg;
+ ecmd->advertising = ADVERTISED_Autoneg;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->autoneg = AUTONEG_ENABLE;
+
+ switch (link_type) {
+ case QETH_LINK_TYPE_FAST_ETH:
+ case QETH_LINK_TYPE_LANE_ETH100:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_TP;
+ ecmd->speed = SPEED_100;
+ ecmd->port = PORT_TP;
+ break;
+
+ case QETH_LINK_TYPE_GBIT_ETH:
+ case QETH_LINK_TYPE_LANE_ETH1000:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE;
+ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_FIBRE;
+ break;
+
+ case QETH_LINK_TYPE_10GBIT_ETH:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE;
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ break;
+
+ default:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_TP;
+ ecmd->speed = SPEED_10;
+ ecmd->port = PORT_TP;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);
+
static int __init qeth_core_init(void)
{
int rc;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 3921d1631a78..86ec50ddae13 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -22,9 +22,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
-#define QETH_DBF_TXT_BUF qeth_l2_dbf_txt_buf
-static DEFINE_PER_CPU(char[256], qeth_l2_dbf_txt_buf);
-
static int qeth_l2_set_offline(struct ccwgroup_device *);
static int qeth_l2_stop(struct net_device *);
static int qeth_l2_send_delmac(struct qeth_card *, __u8 *);
@@ -635,8 +632,6 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
- QETH_DBF_TEXT(TRACE, 6, "l2xmit");
-
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_carrier_errors++;
goto tx_drop;
@@ -658,9 +653,12 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data;
else {
- new_skb = qeth_prepare_skb(card, skb, &hdr);
+ /* create a clone with writeable headroom */
+ new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr));
if (!new_skb)
goto tx_drop;
+ hdr = (struct qeth_hdr *)skb_push(new_skb,
+ sizeof(struct qeth_hdr));
qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
}
@@ -747,7 +745,6 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
int index;
int i;
- QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@@ -852,6 +849,22 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
return;
}
+static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+ struct qeth_card *card = netdev_priv(dev);
+
+ if (data) {
+ if (card->options.large_send == QETH_LARGE_SEND_NO) {
+ card->options.large_send = QETH_LARGE_SEND_EDDP;
+ dev->features |= NETIF_F_TSO;
+ }
+ } else {
+ dev->features &= ~NETIF_F_TSO;
+ card->options.large_send = QETH_LARGE_SEND_NO;
+ }
+ return 0;
+}
+
static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_tx_csum = ethtool_op_get_tx_csum,
@@ -859,11 +872,12 @@ static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .set_tso = qeth_l2_ethtool_set_tso,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
+ .get_settings = qeth_core_ethtool_get_settings,
};
static struct ethtool_ops qeth_l2_osn_ops = {
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 1be353593a59..9f143c83bba3 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -13,9 +13,6 @@
#include "qeth_core.h"
-#define QETH_DBF_TXT_BUF qeth_l3_dbf_txt_buf
-DECLARE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
-
struct qeth_ipaddr {
struct list_head entry;
enum qeth_ip_types type;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e1bfe56087d6..94a8ead64ed4 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -28,8 +28,6 @@
#include "qeth_l3.h"
#include "qeth_core_offl.h"
-DEFINE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
-
static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_recover(void *);
static int qeth_l3_stop(struct net_device *);
@@ -2093,6 +2091,11 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
(card->state == CARD_STATE_UP)) {
if (recovery_mode)
qeth_l3_stop(card->dev);
+ else {
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
+ }
if (!card->use_hard_stop) {
rc = qeth_send_stoplan(card);
if (rc)
@@ -2559,8 +2562,6 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
- QETH_DBF_TEXT(TRACE, 6, "fillhdr");
-
memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
hdr->hdr.l3.ext_flags = 0;
@@ -2570,9 +2571,10 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
* v6 uses passthrough, v4 sets the tag in the QDIO header.
*/
if (card->vlangrp && vlan_tx_tag_present(skb)) {
- hdr->hdr.l3.ext_flags = (ipv == 4) ?
- QETH_HDR_EXT_VLAN_FRAME :
- QETH_HDR_EXT_INCLUDE_VLAN_TAG;
+ if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))
+ hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;
+ else
+ hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG;
hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb);
}
@@ -2638,8 +2640,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
- QETH_DBF_TEXT(TRACE, 6, "l3xmit");
-
if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(skb->protocol != htons(ETH_P_IPV6)) &&
(skb->protocol != htons(ETH_P_IP)))
@@ -2890,6 +2890,7 @@ static struct ethtool_ops qeth_l3_ethtool_ops = {
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
+ .get_settings = qeth_core_ethtool_get_settings,
};
/*
@@ -2982,7 +2983,6 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
int index;
int i;
- QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@@ -3140,9 +3140,15 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
netif_carrier_on(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
- if ((recover_flag == CARD_STATE_RECOVER) && recovery_mode) {
+ if (recover_flag == CARD_STATE_RECOVER) {
+ if (recovery_mode)
qeth_l3_open(card->dev);
- qeth_l3_set_multicast_list(card->dev);
+ else {
+ rtnl_lock();
+ dev_open(card->dev);
+ rtnl_unlock();
+ }
+ qeth_l3_set_multicast_list(card->dev);
}
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 4d4b54277c43..5080f343ad74 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -48,10 +48,11 @@ s390_collect_crw_info(void *param)
int ccode;
struct semaphore *sem;
unsigned int chain;
+ int ignore;
sem = (struct semaphore *)param;
repeat:
- down_interruptible(sem);
+ ignore = down_interruptible(sem);
chain = 0;
while (1) {
if (unlikely(chain > 1)) {
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 37b85c67b11d..c8bad675dbd1 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -1055,7 +1055,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level,
rec->scsi_result = scsi_cmnd->result;
rec->scsi_cmnd = (unsigned long)scsi_cmnd;
rec->scsi_serial = scsi_cmnd->serial_number;
- memcpy(rec->scsi_opcode, &scsi_cmnd->cmnd,
+ memcpy(rec->scsi_opcode, scsi_cmnd->cmnd,
min((int)scsi_cmnd->cmd_len,
ZFCP_DBF_SCSI_OPCODE));
rec->scsi_retries = scsi_cmnd->retries;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 9af2330f07a2..b2ea4ea051f5 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4014,7 +4014,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
scpnt->result);
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (void *) &scpnt->cmnd, scpnt->cmd_len);
+ scpnt->cmnd, scpnt->cmd_len);
ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
fcp_rsp_iu->fcp_sns_len);
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 4fab0c23814c..b87037ec9805 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -41,7 +41,7 @@
#define BPP_DELAY 100
static const unsigned BPP_MAJOR = LP_MAJOR;
-static const char* dev_name = "bpp";
+static const char *bpp_dev_name = "bpp";
/* When switching from compatibility to a mode where I can read, try
the following mode first. */
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index a4e758143665..235703414370 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -637,7 +637,7 @@ static int wd_inittimer(int whichdog)
break;
default:
printk("%s: %s: invalid watchdog id: %i\n",
- WD_OBPNAME, __FUNCTION__, whichdog);
+ WD_OBPNAME, __func__, whichdog);
return(1);
}
if(0 != misc_register(whichmisc))
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 44d2ef906ac7..383f32c1d347 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -393,13 +393,13 @@ static int __init ts102_uctrl_init(void)
err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
if (err) {
printk("%s: unable to register irq %d\n",
- __FUNCTION__, driver->irq);
+ __func__, driver->irq);
return err;
}
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
- __FUNCTION__, uctrl_dev.minor);
+ __func__, uctrl_dev.minor);
free_irq(driver->irq, driver);
return -ENODEV;
}
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index f4c4fe90240a..f5a9addb7050 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -599,7 +599,7 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
(struct NCR_700_command_slot *)SCp->host_scribble;
dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ MAX_COMMAND_SIZE, DMA_TO_DEVICE);
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_700_DEBUG
@@ -1004,7 +1004,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
* here */
NCR_700_unmap(hostdata, SCp, slot);
dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd),
+ MAX_COMMAND_SIZE,
DMA_TO_DEVICE);
cmnd[0] = REQUEST_SENSE;
@@ -1901,7 +1901,7 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
}
slot->resume_offset = 0;
slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ MAX_COMMAND_SIZE, DMA_TO_DEVICE);
NCR_700_start_command(SCp);
return 0;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 99c57b0c1d54..81ccbd7f9e34 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -504,10 +504,9 @@ config SCSI_AIC7XXX_OLD
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
-# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
tristate "Adaptec I2O RAID support "
- depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
+ depends on SCSI && PCI && VIRT_TO_BUS
help
This driver supports all of Adaptec's I2O based RAID controllers as
well as the DPT SmartRaid V cards. This is an Adaptec maintained
@@ -1680,6 +1679,7 @@ config MAC_SCSI
config SCSI_MAC_ESP
tristate "Macintosh NCR53c9[46] SCSI"
depends on MAC && SCSI
+ select SCSI_SPI_ATTRS
help
This is the NCR 53c9x SCSI controller found on most of the 68040
based Macintoshes.
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 792b2e807bf3..ced3eebe252c 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -895,7 +895,7 @@ static void inia100_build_scb(struct orc_host * host, struct orc_scb * scb, stru
} else {
scb->tag_msg = 0; /* No tag support */
}
- memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len);
+ memcpy(scb->cdb, cmd->cmnd, scb->cdb_len);
}
/**
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 460d4024c46c..aa4e77c25273 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -498,6 +498,11 @@ static void _aac_probe_container2(void * context, struct fib * fibptr)
(le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
(le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
fsa_dev_ptr->valid = 1;
+ /* sense_key holds the current state of the spin-up */
+ if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
+ fsa_dev_ptr->sense_data.sense_key = NOT_READY;
+ else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
+ fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
fsa_dev_ptr->size
= ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
@@ -1509,20 +1514,35 @@ static void io_callback(void *context, struct fib * fibptr)
scsi_dma_unmap(scsicmd);
readreply = (struct aac_read_reply *)fib_data(fibptr);
- if (le32_to_cpu(readreply->status) == ST_OK)
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
- else {
+ switch (le32_to_cpu(readreply->status)) {
+ case ST_OK:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
+ break;
+ case ST_NOT_READY:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
+ SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
+ memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+ min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+ SCSI_SENSE_BUFFERSIZE));
+ break;
+ default:
#ifdef AAC_DETAILED_STATUS_INFO
printk(KERN_WARNING "io_callback: io failed, status = %d\n",
le32_to_cpu(readreply->status));
#endif
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
set_sense(&dev->fsa_dev[cid].sense_data,
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
+ break;
}
aac_fib_complete(fibptr);
aac_fib_free(fibptr);
@@ -1863,6 +1883,84 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
return SCSI_MLQUEUE_HOST_BUSY;
}
+static void aac_start_stop_callback(void *context, struct fib *fibptr)
+{
+ struct scsi_cmnd *scsicmd = context;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
+ BUG_ON(fibptr == NULL);
+
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ scsicmd->scsi_done(scsicmd);
+}
+
+static int aac_start_stop(struct scsi_cmnd *scsicmd)
+{
+ int status;
+ struct fib *cmd_fibcontext;
+ struct aac_power_management *pmcmd;
+ struct scsi_device *sdev = scsicmd->device;
+ struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+
+ if (!(aac->supplement_adapter_info.SupportedOptions2 &
+ AAC_OPTION_POWER_MANAGEMENT)) {
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
+
+ if (aac->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ /*
+ * Allocate and initialize a Fib
+ */
+ cmd_fibcontext = aac_fib_alloc(aac);
+ if (!cmd_fibcontext)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ aac_fib_init(cmd_fibcontext);
+
+ pmcmd = fib_data(cmd_fibcontext);
+ pmcmd->command = cpu_to_le32(VM_ContainerConfig);
+ pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
+ /* Eject bit ignored, not relevant */
+ pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
+ cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
+ pmcmd->cid = cpu_to_le32(sdev_id(sdev));
+ pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
+ cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
+
+ /*
+ * Now send the Fib to the adapter
+ */
+ status = aac_fib_send(ContainerCommand,
+ cmd_fibcontext,
+ sizeof(struct aac_power_management),
+ FsaNormal,
+ 0, 1,
+ (fib_callback)aac_start_stop_callback,
+ (void *)scsicmd);
+
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+
+ aac_fib_complete(cmd_fibcontext);
+ aac_fib_free(cmd_fibcontext);
+ return SCSI_MLQUEUE_HOST_BUSY;
+}
+
/**
* aac_scsi_cmd() - Process SCSI command
* @scsicmd: SCSI command block
@@ -1899,7 +1997,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* If the target container doesn't exist, it may have
* been newly created
*/
- if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+ if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
+ (fsa_dev_ptr[cid].sense_data.sense_key ==
+ NOT_READY)) {
switch (scsicmd->cmnd[0]) {
case SERVICE_ACTION_IN:
if (!(dev->raw_io_interface) ||
@@ -2091,8 +2191,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
/* Do not cache partition table for arrays */
scsicmd->device->removable = 1;
-
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
@@ -2187,15 +2287,32 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* These commands are all No-Ops
*/
case TEST_UNIT_READY:
+ if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ NOT_READY, SENCODE_BECOMING_READY,
+ ASENCODE_BECOMING_READY, 0, 0);
+ memcpy(scsicmd->sense_buffer,
+ &dev->fsa_dev[cid].sense_data,
+ min_t(size_t,
+ sizeof(dev->fsa_dev[cid].sense_data),
+ SCSI_SENSE_BUFFERSIZE));
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
+ /* FALLTHRU */
case RESERVE:
case RELEASE:
case REZERO_UNIT:
case REASSIGN_BLOCKS:
case SEEK_10:
- case START_STOP:
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
+
+ case START_STOP:
+ return aac_start_stop(scsicmd);
}
switch (scsicmd->cmnd[0])
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 113ca9c8934c..73916adb8f80 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2455
+# define AAC_DRIVER_BUILD 2456
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -34,8 +34,8 @@
#define CONTAINER_TO_ID(cont) (cont)
#define CONTAINER_TO_LUN(cont) (0)
-#define aac_phys_to_logical(x) (x+1)
-#define aac_logical_to_phys(x) (x?x-1:0)
+#define aac_phys_to_logical(x) ((x)+1)
+#define aac_logical_to_phys(x) ((x)?(x)-1:0)
/* #define AAC_DETAILED_STATUS_INFO */
@@ -424,6 +424,8 @@ struct aac_init
*/
__le32 InitFlags; /* flags for supported features */
#define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001
+#define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010
+#define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020
__le32 MaxIoCommands; /* max outstanding commands */
__le32 MaxIoSize; /* largest I/O command */
__le32 MaxFibSize; /* largest FIB to adapter */
@@ -867,8 +869,10 @@ struct aac_supplement_adapter_info
};
#define AAC_FEATURE_FALCON cpu_to_le32(0x00000010)
#define AAC_FEATURE_JBOD cpu_to_le32(0x08000000)
-#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001)
-#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002)
+/* SupportedOptions2 */
+#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001)
+#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002)
+#define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004)
#define AAC_SIS_VERSION_V3 3
#define AAC_SIS_SLOT_UNKNOWN 0xFF
@@ -1148,6 +1152,7 @@ struct aac_dev
#define ST_DQUOT 69
#define ST_STALE 70
#define ST_REMOTE 71
+#define ST_NOT_READY 72
#define ST_BADHANDLE 10001
#define ST_NOT_SYNC 10002
#define ST_BAD_COOKIE 10003
@@ -1269,6 +1274,18 @@ struct aac_synchronize_reply {
u8 data[16];
};
+#define CT_POWER_MANAGEMENT 245
+#define CT_PM_START_UNIT 2
+#define CT_PM_STOP_UNIT 3
+#define CT_PM_UNIT_IMMEDIATE 1
+struct aac_power_management {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_POWER_MANAGEMENT */
+ __le32 sub; /* CT_PM_* */
+ __le32 cid;
+ __le32 parm; /* CT_PM_sub_* */
+};
+
#define CT_PAUSE_IO 65
#define CT_RELEASE_IO 66
struct aac_pause {
@@ -1536,6 +1553,7 @@ struct aac_mntent {
#define FSCS_NOTCLEAN 0x0001 /* fsck is necessary before mounting */
#define FSCS_READONLY 0x0002 /* possible result of broken mirror */
#define FSCS_HIDDEN 0x0004 /* should be ignored - set during a clear */
+#define FSCS_NOT_READY 0x0008 /* Array spinning up to fulfil request */
struct aac_query_mount {
__le32 command;
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 294a802450be..cbac06355107 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -97,6 +97,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
}
+ init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
+ INITFLAGS_DRIVER_SUPPORTS_PM);
init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index ef67816a6fe5..289304aab690 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -515,7 +515,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
- } else if (down_interruptible(&fibptr->event_wait) == 0) {
+ } else if (down_interruptible(&fibptr->event_wait)) {
fibptr->done = 2;
up(&fibptr->event_wait);
}
@@ -906,15 +906,22 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case AifEnAddJBOD:
case AifEnDeleteJBOD:
container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
- if (id >= dev->maximum_num_physicals)
+ if (id >= dev->maximum_num_physicals) {
+ container = (u32)-1;
break;
+ }
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
channel = aac_phys_to_logical(channel);
device_config_needed =
(((__le32 *)aifcmd->data)[0] ==
@@ -933,13 +940,18 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case EM_DRIVE_REMOVAL:
container = le32_to_cpu(
((__le32 *)aifcmd->data)[2]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
if (id >= dev->maximum_num_physicals) {
/* legacy dev_t ? */
if ((0x2000 <= id) || lun || channel ||
@@ -1025,9 +1037,10 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
break;
}
+ container = 0;
+retry_next:
if (device_config_needed == NOTHING)
- for (container = 0; container < dev->maximum_num_containers;
- ++container) {
+ for (; container < dev->maximum_num_containers; ++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0) &&
(dev->fsa_dev[container].config_needed != NOTHING) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) {
@@ -1110,6 +1123,11 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
if (device_config_needed == ADD)
scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+ if (channel == CONTAINER_CHANNEL) {
+ container++;
+ device_config_needed = NOTHING;
+ goto retry_next;
+ }
}
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index c109f63f8279..1f7c83607f84 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -401,6 +401,8 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
static int aac_slave_configure(struct scsi_device *sdev)
{
struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+ if (aac->jbod && (sdev->type == TYPE_DISK))
+ sdev->removable = 1;
if ((sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) != CONTAINER_CHANNEL) &&
(!aac->jbod || sdev->inq_periph_qual) &&
@@ -809,6 +811,12 @@ static ssize_t aac_show_flags(struct device *cdev,
"SAI_READ_CAPACITY_16\n");
if (dev->jbod)
len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
+ if (dev->supplement_adapter_info.SupportedOptions2 &
+ AAC_OPTION_POWER_MANAGEMENT)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "SUPPORTED_POWER_MANAGEMENT\n");
+ if (dev->msi)
+ len += snprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n");
return len;
}
@@ -1106,7 +1114,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
aac->pdev = pdev;
aac->name = aac_driver_template.name;
aac->id = shost->unique_id;
- aac->cardtype = index;
+ aac->cardtype = index;
INIT_LIST_HEAD(&aac->entry);
aac->fibs = kmalloc(sizeof(struct fib) * (shost->can_queue + AAC_NUM_MGT_FIB), GFP_KERNEL);
@@ -1146,19 +1154,19 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
goto out_deinit;
/*
- * Lets override negotiations and drop the maximum SG limit to 34
- */
+ * Lets override negotiations and drop the maximum SG limit to 34
+ */
if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
(shost->sg_tablesize > 34)) {
shost->sg_tablesize = 34;
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
- }
+ }
- if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
+ if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
(shost->sg_tablesize > 17)) {
shost->sg_tablesize = 17;
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
- }
+ }
error = pci_set_dma_max_seg_size(pdev,
(aac->adapter_info.options & AAC_OPT_NEW_COMM) ?
@@ -1174,7 +1182,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
else
aac->printf_enabled = 0;
- /*
+ /*
* max channel will be the physical channels plus 1 virtual channel
* all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
* physical channels are address by their actual physical number+1
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index f5215fd4b73d..1dca1775f4b1 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -3830,7 +3830,7 @@ static int __init aha152x_init(void)
iounmap(p);
}
if (!ok && setup_count == 0)
- return 0;
+ return -ENODEV;
printk(KERN_INFO "aha152x: BIOS test: passed, ");
#else
@@ -3909,14 +3909,14 @@ static int __init aha152x_init(void)
#endif
}
- return 1;
+ return 0;
}
static void __exit aha152x_exit(void)
{
- struct aha152x_hostdata *hd;
+ struct aha152x_hostdata *hd, *tmp;
- list_for_each_entry(hd, &aha152x_host_list, host_list) {
+ list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
aha152x_release(shost);
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 90f5e0a6f2e3..2a730c470f62 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -529,10 +529,10 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
/* The first entry, 0, is used for dynamic ids, the rest for devices
* we know about.
*/
-static struct asd_pcidev_struct {
+static const struct asd_pcidev_struct {
const char * name;
int (*setup)(struct asd_ha_struct *asd_ha);
-} asd_pcidev_data[] = {
+} asd_pcidev_data[] __devinitconst = {
/* Id 0 is used for dynamic ids. */
{ .name = "Adaptec AIC-94xx SAS/SATA Host Adapter",
.setup = asd_aic9410_setup
@@ -735,7 +735,7 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
static int __devinit asd_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- struct asd_pcidev_struct *asd_dev;
+ const struct asd_pcidev_struct *asd_dev;
unsigned asd_id = (unsigned) id->driver_data;
struct asd_ha_struct *asd_ha;
struct Scsi_Host *shost;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 403a7f2d8f9b..9785d7384199 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -28,7 +28,6 @@
#define SERVICE_ACTION_OUT_12 0xa9
#define SERVICE_ACTION_IN_16 0x9e
#define SERVICE_ACTION_OUT_16 0x9f
-#define VARIABLE_LENGTH_CMD 0x7f
@@ -210,7 +209,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
- len = cdbp[7] + 8;
+ len = scsi_varlen_cdb_length(cdbp);
if (len < 10) {
printk("short variable length command, "
"len=%d ext_len=%d", len, cdb_len);
@@ -300,7 +299,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
- len = cdbp[7] + 8;
+ len = scsi_varlen_cdb_length(cdbp);
if (len < 10) {
printk("short opcode=0x%x command, len=%d "
"ext_len=%d", cdb0, len, cdb_len);
@@ -335,10 +334,7 @@ void __scsi_print_command(unsigned char *cdb)
int k, len;
print_opcode_name(cdb, 0);
- if (VARIABLE_LENGTH_CMD == cdb[0])
- len = cdb[7] + 8;
- else
- len = COMMAND_SIZE(cdb[0]);
+ len = scsi_command_size(cdb);
/* print out all bytes in cdb */
for (k = 0; k < len; ++k)
printk(" %02x", cdb[k]);
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index cc784e8f6e9d..f60236721e0d 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -89,7 +89,7 @@ typedef struct {
int njobs; /* # of jobs sent to HA */
int qdepth; /* Controller queue depth. */
int wakebase; /* mpx wakeup base index. */
- uLONG SGsize; /* Scatter/Gather list size. */
+ uINT SGsize; /* Scatter/Gather list size. */
unsigned heads; /* heads for drives on cntlr. */
unsigned sectors; /* sectors for drives on cntlr. */
uCHAR do_drive32; /* Flag for Above 16 MB Ability */
@@ -97,8 +97,8 @@ typedef struct {
char idPAL[4]; /* 4 Bytes Of The ID Pal */
uCHAR primary; /* 1 For Primary, 0 For Secondary */
uCHAR eataVersion; /* EATA Version */
- uLONG cpLength; /* EATA Command Packet Length */
- uLONG spLength; /* EATA Status Packet Length */
+ uINT cpLength; /* EATA Command Packet Length */
+ uINT spLength; /* EATA Status Packet Length */
uCHAR drqNum; /* DRQ Index (0,5,6,7) */
uCHAR flag1; /* EATA Flags 1 (Byte 9) */
uCHAR flag2; /* EATA Flags 2 (Byte 30) */
@@ -107,23 +107,23 @@ typedef struct {
typedef struct {
uSHORT length; // Remaining length of this
uSHORT drvrHBAnum; // Relative HBA # used by the driver
- uLONG baseAddr; // Base I/O address
+ uINT baseAddr; // Base I/O address
uSHORT blinkState; // Blink LED state (0=Not in blink LED)
uCHAR pciBusNum; // PCI Bus # (Optional)
uCHAR pciDeviceNum; // PCI Device # (Optional)
uSHORT hbaFlags; // Miscellaneous HBA flags
uSHORT Interrupt; // Interrupt set for this device.
# if (defined(_DPT_ARC))
- uLONG baseLength;
+ uINT baseLength;
ADAPTER_OBJECT *AdapterObject;
LARGE_INTEGER DmaLogicalAddress;
PVOID DmaVirtualAddress;
LARGE_INTEGER ReplyLogicalAddress;
PVOID ReplyVirtualAddress;
# else
- uLONG reserved1; // Reserved for future expansion
- uLONG reserved2; // Reserved for future expansion
- uLONG reserved3; // Reserved for future expansion
+ uINT reserved1; // Reserved for future expansion
+ uINT reserved2; // Reserved for future expansion
+ uINT reserved3; // Reserved for future expansion
# endif
} drvrHBAinfo_S;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 94bc894d1200..72c8992fdf21 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -33,11 +33,7 @@
/* to make sure we are talking the same size under all OS's */
typedef unsigned char sigBYTE;
typedef unsigned short sigWORD;
-#if (defined(_MULTI_DATAMODEL) && defined(sun) && !defined(_ILP32))
-typedef uint32_t sigLONG;
-#else
-typedef unsigned long sigLONG;
-#endif
+typedef unsigned int sigINT;
/*
* use sigWORDLittleEndian for:
@@ -300,7 +296,7 @@ typedef struct dpt_sig {
sigBYTE dsFiletype; /* type of file */
sigBYTE dsFiletypeFlags; /* flags to specify load type, etc. */
sigBYTE dsOEM; /* OEM file was created for */
- sigLONG dsOS; /* which Operating systems */
+ sigINT dsOS; /* which Operating systems */
sigWORD dsCapabilities; /* RAID levels, etc. */
sigWORD dsDeviceSupp; /* Types of SCSI devices supported */
sigWORD dsAdapterSupp; /* DPT adapter families supported */
diff --git a/drivers/scsi/dpt/sys_info.h b/drivers/scsi/dpt/sys_info.h
index d23b70c8c768..a90c4cb8ea8b 100644
--- a/drivers/scsi/dpt/sys_info.h
+++ b/drivers/scsi/dpt/sys_info.h
@@ -145,8 +145,8 @@
uCHAR smartROMRevision;
uSHORT flags; /* See bit definitions above */
uSHORT conventionalMemSize; /* in KB */
- uLONG extendedMemSize; /* in KB */
- uLONG osType; /* Same as DPTSIG's definition */
+ uINT extendedMemSize; /* in KB */
+ uINT osType; /* Same as DPTSIG's definition */
uCHAR osMajorVersion;
uCHAR osMinorVersion; /* The OS version */
uCHAR osRevision;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index ac92ac143b46..8508816f303d 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -29,11 +29,6 @@
/*#define DEBUG 1 */
/*#define UARTDELAY 1 */
-/* On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
- high pages. Keep the macro around because of the broken unmerged ia64 tree */
-
-#define ADDR32 (0)
-
#include <linux/module.h>
MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
@@ -108,27 +103,28 @@ static dpt_sig_S DPTI_sig = {
static DEFINE_MUTEX(adpt_configuration_lock);
-static struct i2o_sys_tbl *sys_tbl = NULL;
-static int sys_tbl_ind = 0;
-static int sys_tbl_len = 0;
+static struct i2o_sys_tbl *sys_tbl;
+static dma_addr_t sys_tbl_pa;
+static int sys_tbl_ind;
+static int sys_tbl_len;
static adpt_hba* hba_chain = NULL;
static int hba_count = 0;
+static struct class *adpt_sysfs_class;
+
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long);
+#endif
+
static const struct file_operations adpt_fops = {
.ioctl = adpt_ioctl,
.open = adpt_open,
- .release = adpt_close
-};
-
-#ifdef REBOOT_NOTIFIER
-static struct notifier_block adpt_reboot_notifier =
-{
- adpt_reboot_event,
- NULL,
- 0
-};
+ .release = adpt_close,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_adpt_ioctl,
#endif
+};
/* Structures and definitions for synchronous message posting.
* See adpt_i2o_post_wait() for description
@@ -151,6 +147,21 @@ static DEFINE_SPINLOCK(adpt_post_wait_lock);
*============================================================================
*/
+static inline int dpt_dma64(adpt_hba *pHba)
+{
+ return (sizeof(dma_addr_t) > 4 && (pHba)->dma64);
+}
+
+static inline u32 dma_high(dma_addr_t addr)
+{
+ return upper_32_bits(addr);
+}
+
+static inline u32 dma_low(dma_addr_t addr)
+{
+ return (u32)addr;
+}
+
static u8 adpt_read_blink_led(adpt_hba* host)
{
if (host->FwDebugBLEDflag_P) {
@@ -178,8 +189,6 @@ static int adpt_detect(struct scsi_host_template* sht)
struct pci_dev *pDev = NULL;
adpt_hba* pHba;
- adpt_init();
-
PINFO("Detecting Adaptec I2O RAID controllers...\n");
/* search for all Adatpec I2O RAID cards */
@@ -247,13 +256,29 @@ rebuild_sys_tab:
adpt_inquiry(pHba);
}
+ adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o");
+ if (IS_ERR(adpt_sysfs_class)) {
+ printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n");
+ adpt_sysfs_class = NULL;
+ }
+
for (pHba = hba_chain; pHba; pHba = pHba->next) {
- if( adpt_scsi_register(pHba,sht) < 0){
+ if (adpt_scsi_host_alloc(pHba, sht) < 0){
adpt_i2o_delete_hba(pHba);
continue;
}
pHba->initialized = TRUE;
pHba->state &= ~DPTI_STATE_RESET;
+ if (adpt_sysfs_class) {
+ struct device *dev = device_create(adpt_sysfs_class,
+ NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit),
+ "dpti%d", pHba->unit);
+ if (IS_ERR(dev)) {
+ printk(KERN_WARNING"dpti%d: unable to "
+ "create device in dpt_i2o class\n",
+ pHba->unit);
+ }
+ }
}
// Register our control device node
@@ -282,7 +307,7 @@ static int adpt_release(struct Scsi_Host *host)
static void adpt_inquiry(adpt_hba* pHba)
{
- u32 msg[14];
+ u32 msg[17];
u32 *mptr;
u32 *lenptr;
int direction;
@@ -290,11 +315,12 @@ static void adpt_inquiry(adpt_hba* pHba)
u32 len;
u32 reqlen;
u8* buf;
+ dma_addr_t addr;
u8 scb[16];
s32 rcode;
memset(msg, 0, sizeof(msg));
- buf = kmalloc(80,GFP_KERNEL|ADDR32);
+ buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL);
if(!buf){
printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
return;
@@ -305,7 +331,10 @@ static void adpt_inquiry(adpt_hba* pHba)
direction = 0x00000000;
scsidir =0x40000000; // DATA IN (iop<--dev)
- reqlen = 14; // SINGLE SGE
+ if (dpt_dma64(pHba))
+ reqlen = 17; // SINGLE SGE, 64 bit
+ else
+ reqlen = 14; // SINGLE SGE, 32 bit
/* Stick the headers on */
msg[0] = reqlen<<16 | SGL_OFFSET_12;
msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID);
@@ -338,8 +367,16 @@ static void adpt_inquiry(adpt_hba* pHba)
/* Now fill in the SGList and command */
*lenptr = len;
- *mptr++ = 0xD0000000|direction|len;
- *mptr++ = virt_to_bus(buf);
+ if (dpt_dma64(pHba)) {
+ *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+ *mptr++ = 1 << PAGE_SHIFT;
+ *mptr++ = 0xD0000000|direction|len;
+ *mptr++ = dma_low(addr);
+ *mptr++ = dma_high(addr);
+ } else {
+ *mptr++ = 0xD0000000|direction|len;
+ *mptr++ = addr;
+ }
// Send it on it's way
rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120);
@@ -347,7 +384,7 @@ static void adpt_inquiry(adpt_hba* pHba)
sprintf(pHba->detail, "Adaptec I2O RAID");
printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
if (rcode != -ETIME && rcode != -EINTR)
- kfree(buf);
+ dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
} else {
memset(pHba->detail, 0, sizeof(pHba->detail));
memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
@@ -356,7 +393,7 @@ static void adpt_inquiry(adpt_hba* pHba)
memcpy(&(pHba->detail[40]), " FW: ", 4);
memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
pHba->detail[48] = '\0'; /* precautionary */
- kfree(buf);
+ dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
}
adpt_i2o_status_get(pHba);
return ;
@@ -632,6 +669,91 @@ stop_output:
return len;
}
+/*
+ * Turn a struct scsi_cmnd * into a unique 32 bit 'context'.
+ */
+static u32 adpt_cmd_to_context(struct scsi_cmnd *cmd)
+{
+ return (u32)cmd->serial_number;
+}
+
+/*
+ * Go from a u32 'context' to a struct scsi_cmnd * .
+ * This could probably be made more efficient.
+ */
+static struct scsi_cmnd *
+ adpt_cmd_from_context(adpt_hba * pHba, u32 context)
+{
+ struct scsi_cmnd * cmd;
+ struct scsi_device * d;
+
+ if (context == 0)
+ return NULL;
+
+ spin_unlock(pHba->host->host_lock);
+ shost_for_each_device(d, pHba->host) {
+ unsigned long flags;
+ spin_lock_irqsave(&d->list_lock, flags);
+ list_for_each_entry(cmd, &d->cmd_list, list) {
+ if (((u32)cmd->serial_number == context)) {
+ spin_unlock_irqrestore(&d->list_lock, flags);
+ scsi_device_put(d);
+ spin_lock(pHba->host->host_lock);
+ return cmd;
+ }
+ }
+ spin_unlock_irqrestore(&d->list_lock, flags);
+ }
+ spin_lock(pHba->host->host_lock);
+
+ return NULL;
+}
+
+/*
+ * Turn a pointer to ioctl reply data into an u32 'context'
+ */
+static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply)
+{
+#if BITS_PER_LONG == 32
+ return (u32)(unsigned long)reply;
+#else
+ ulong flags = 0;
+ u32 nr, i;
+
+ spin_lock_irqsave(pHba->host->host_lock, flags);
+ nr = ARRAY_SIZE(pHba->ioctl_reply_context);
+ for (i = 0; i < nr; i++) {
+ if (pHba->ioctl_reply_context[i] == NULL) {
+ pHba->ioctl_reply_context[i] = reply;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(pHba->host->host_lock, flags);
+ if (i >= nr) {
+ kfree (reply);
+ printk(KERN_WARNING"%s: Too many outstanding "
+ "ioctl commands\n", pHba->name);
+ return (u32)-1;
+ }
+
+ return i;
+#endif
+}
+
+/*
+ * Go from an u32 'context' to a pointer to ioctl reply data.
+ */
+static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context)
+{
+#if BITS_PER_LONG == 32
+ return (void *)(unsigned long)context;
+#else
+ void *p = pHba->ioctl_reply_context[context];
+ pHba->ioctl_reply_context[context] = NULL;
+
+ return p;
+#endif
+}
/*===========================================================================
* Error Handling routines
@@ -660,7 +782,7 @@ static int adpt_abort(struct scsi_cmnd * cmd)
msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid;
msg[2] = 0;
msg[3]= 0;
- msg[4] = (u32)cmd;
+ msg[4] = adpt_cmd_to_context(cmd);
if (pHba->host)
spin_lock_irq(pHba->host->host_lock);
rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER);
@@ -861,27 +983,6 @@ static void adpt_i2o_sys_shutdown(void)
printk(KERN_INFO "Adaptec I2O controllers down.\n");
}
-/*
- * reboot/shutdown notification.
- *
- * - Quiesce each IOP in the system
- *
- */
-
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p)
-{
-
- if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
- return NOTIFY_DONE;
-
- adpt_i2o_sys_shutdown();
-
- return NOTIFY_DONE;
-}
-#endif
-
-
static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
{
@@ -893,6 +994,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
u32 hba_map1_area_size = 0;
void __iomem *base_addr_virt = NULL;
void __iomem *msg_addr_virt = NULL;
+ int dma64 = 0;
int raptorFlag = FALSE;
@@ -906,9 +1008,21 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
}
pci_set_master(pDev);
- if (pci_set_dma_mask(pDev, DMA_32BIT_MASK))
+
+ /*
+ * See if we should enable dma64 mode.
+ */
+ if (sizeof(dma_addr_t) > 4 &&
+ pci_set_dma_mask(pDev, DMA_64BIT_MASK) == 0) {
+ if (dma_get_required_mask(&pDev->dev) > DMA_32BIT_MASK)
+ dma64 = 1;
+ }
+ if (!dma64 && pci_set_dma_mask(pDev, DMA_32BIT_MASK) != 0)
return -EINVAL;
+ /* adapter only supports message blocks below 4GB */
+ pci_set_consistent_dma_mask(pDev, DMA_32BIT_MASK);
+
base_addr0_phys = pci_resource_start(pDev,0);
hba_map0_area_size = pci_resource_len(pDev,0);
@@ -929,6 +1043,25 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
raptorFlag = TRUE;
}
+#if BITS_PER_LONG == 64
+ /*
+ * The original Adaptec 64 bit driver has this comment here:
+ * "x86_64 machines need more optimal mappings"
+ *
+ * I assume some HBAs report ridiculously large mappings
+ * and we need to limit them on platforms with IOMMUs.
+ */
+ if (raptorFlag == TRUE) {
+ if (hba_map0_area_size > 128)
+ hba_map0_area_size = 128;
+ if (hba_map1_area_size > 524288)
+ hba_map1_area_size = 524288;
+ } else {
+ if (hba_map0_area_size > 524288)
+ hba_map0_area_size = 524288;
+ }
+#endif
+
base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
if (!base_addr_virt) {
pci_release_regions(pDev);
@@ -991,16 +1124,22 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
pHba->state = DPTI_STATE_RESET;
pHba->pDev = pDev;
pHba->devices = NULL;
+ pHba->dma64 = dma64;
// Initializing the spinlocks
spin_lock_init(&pHba->state_lock);
spin_lock_init(&adpt_post_wait_lock);
if(raptorFlag == 0){
- printk(KERN_INFO"Adaptec I2O RAID controller %d at %p size=%x irq=%d\n",
- hba_count-1, base_addr_virt, hba_map0_area_size, pDev->irq);
+ printk(KERN_INFO "Adaptec I2O RAID controller"
+ " %d at %p size=%x irq=%d%s\n",
+ hba_count-1, base_addr_virt,
+ hba_map0_area_size, pDev->irq,
+ dma64 ? " (64-bit DMA)" : "");
} else {
- printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d\n",hba_count-1, pDev->irq);
+ printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n",
+ hba_count-1, pDev->irq,
+ dma64 ? " (64-bit DMA)" : "");
printk(KERN_INFO" BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size);
printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
}
@@ -1053,10 +1192,26 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
if(pHba->msg_addr_virt != pHba->base_addr_virt){
iounmap(pHba->msg_addr_virt);
}
- kfree(pHba->hrt);
- kfree(pHba->lct);
- kfree(pHba->status_block);
- kfree(pHba->reply_pool);
+ if(pHba->FwDebugBuffer_P)
+ iounmap(pHba->FwDebugBuffer_P);
+ if(pHba->hrt) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->hrt->num_entries * pHba->hrt->entry_len << 2,
+ pHba->hrt, pHba->hrt_pa);
+ }
+ if(pHba->lct) {
+ dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+ pHba->lct, pHba->lct_pa);
+ }
+ if(pHba->status_block) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block),
+ pHba->status_block, pHba->status_block_pa);
+ }
+ if(pHba->reply_pool) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ pHba->reply_pool, pHba->reply_pool_pa);
+ }
for(d = pHba->devices; d ; d = next){
next = d->next;
@@ -1075,23 +1230,19 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
pci_dev_put(pHba->pDev);
kfree(pHba);
+ if (adpt_sysfs_class)
+ device_destroy(adpt_sysfs_class,
+ MKDEV(DPTI_I2O_MAJOR, pHba->unit));
+
if(hba_count <= 0){
unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);
+ if (adpt_sysfs_class) {
+ class_destroy(adpt_sysfs_class);
+ adpt_sysfs_class = NULL;
+ }
}
}
-
-static int adpt_init(void)
-{
- printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
-#ifdef REBOOT_NOTIFIER
- register_reboot_notifier(&adpt_reboot_notifier);
-#endif
-
- return 0;
-}
-
-
static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun)
{
struct adpt_device* d;
@@ -1283,6 +1434,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
{
u32 msg[8];
u8* status;
+ dma_addr_t addr;
u32 m = EMPTY_QUEUE ;
ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);
@@ -1305,12 +1457,13 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
schedule_timeout_uninterruptible(1);
} while (m == EMPTY_QUEUE);
- status = kzalloc(4, GFP_KERNEL|ADDR32);
+ status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
if(status == NULL) {
adpt_send_nop(pHba, m);
printk(KERN_ERR"IOP reset failed - no free memory.\n");
return -ENOMEM;
}
+ memset(status,0,4);
msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1318,8 +1471,8 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
msg[3]=0;
msg[4]=0;
msg[5]=0;
- msg[6]=virt_to_bus(status);
- msg[7]=0;
+ msg[6]=dma_low(addr);
+ msg[7]=dma_high(addr);
memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));
wmb();
@@ -1329,7 +1482,10 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
while(*status == 0){
if(time_after(jiffies,timeout)){
printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);
- kfree(status);
+ /* We lose 4 bytes of "status" here, but we cannot
+ free these because controller may awake and corrupt
+ those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
return -ETIMEDOUT;
}
rmb();
@@ -1348,6 +1504,10 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
}
if(time_after(jiffies,timeout)){
printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
+ /* We lose 4 bytes of "status" here, but we
+ cannot free these because controller may
+ awake and corrupt those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -1364,7 +1524,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
PDEBUG("%s: Reset completed.\n", pHba->name);
}
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
#ifdef UARTDELAY
// This delay is to allow someone attached to the card through the debug UART to
// set up the dump levels that they want before the rest of the initialization sequence
@@ -1636,6 +1796,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
u32 i = 0;
u32 rcode = 0;
void *p = NULL;
+ dma_addr_t addr;
ulong flags = 0;
memset(&msg, 0, MAX_MESSAGE_SIZE*4);
@@ -1668,10 +1829,13 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
sg_offset = (msg[0]>>4)&0xf;
msg[2] = 0x40000000; // IOCTL context
- msg[3] = (u32)reply;
+ msg[3] = adpt_ioctl_to_context(pHba, reply);
+ if (msg[3] == (u32)-1)
+ return -EBUSY;
+
memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize);
if(sg_offset) {
- // TODO 64bit fix
+ // TODO add 64 bit API
struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset);
sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
if (sg_count > pHba->sg_tablesize){
@@ -1690,7 +1854,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
sg_size = sg[i].flag_count & 0xffffff;
/* Allocate memory for the transfer */
- p = kmalloc(sg_size, GFP_KERNEL|ADDR32);
+ p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL);
if(!p) {
printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
pHba->name,sg_size,i,sg_count);
@@ -1700,15 +1864,15 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
/* Copy in the user's SG buffer if necessary */
if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
- // TODO 64bit fix
- if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) {
+ // sg_simple_element API is 32 bit
+ if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) {
printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
rcode = -EFAULT;
goto cleanup;
}
}
- //TODO 64bit fix
- sg[i].addr_bus = (u32)virt_to_bus(p);
+ /* sg_simple_element API is 32 bit, but addr < 4GB */
+ sg[i].addr_bus = addr;
}
}
@@ -1736,7 +1900,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
if(sg_offset) {
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
- // TODO 64bit fix
+ // TODO add 64 bit API
struct sg_simple_element* sg;
int sg_size;
@@ -1756,14 +1920,14 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
- // TODO 64bit fix
+ // TODO add 64 bit API
sg = (struct sg_simple_element*)(msg + sg_offset);
for (j = 0; j < sg_count; j++) {
/* Copy out the SG list to user's buffer if necessary */
if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
sg_size = sg[j].flag_count & 0xffffff;
- // TODO 64bit fix
- if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) {
+ // sg_simple_element API is 32 bit
+ if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {
printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
rcode = -EFAULT;
goto cleanup;
@@ -1787,56 +1951,22 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
cleanup:
- if (rcode != -ETIME && rcode != -EINTR)
+ if (rcode != -ETIME && rcode != -EINTR) {
+ struct sg_simple_element *sg =
+ (struct sg_simple_element*) (msg +sg_offset);
kfree (reply);
- while(sg_index) {
- if(sg_list[--sg_index]) {
- if (rcode != -ETIME && rcode != -EINTR)
- kfree(sg_list[sg_index]);
+ while(sg_index) {
+ if(sg_list[--sg_index]) {
+ dma_free_coherent(&pHba->pDev->dev,
+ sg[sg_index].flag_count & 0xffffff,
+ sg_list[sg_index],
+ sg[sg_index].addr_bus);
+ }
}
}
return rcode;
}
-
-/*
- * This routine returns information about the system. This does not effect
- * any logic and if the info is wrong - it doesn't matter.
- */
-
-/* Get all the info we can not get from kernel services */
-static int adpt_system_info(void __user *buffer)
-{
- sysInfo_S si;
-
- memset(&si, 0, sizeof(si));
-
- si.osType = OS_LINUX;
- si.osMajorVersion = 0;
- si.osMinorVersion = 0;
- si.osRevision = 0;
- si.busType = SI_PCI_BUS;
- si.processorFamily = DPTI_sig.dsProcessorFamily;
-
-#if defined __i386__
- adpt_i386_info(&si);
-#elif defined (__ia64__)
- adpt_ia64_info(&si);
-#elif defined(__sparc__)
- adpt_sparc_info(&si);
-#elif defined (__alpha__)
- adpt_alpha_info(&si);
-#else
- si.processorType = 0xff ;
-#endif
- if(copy_to_user(buffer, &si, sizeof(si))){
- printk(KERN_WARNING"dpti: Could not copy buffer TO user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
#if defined __ia64__
static void adpt_ia64_info(sysInfo_S* si)
{
@@ -1847,7 +1977,6 @@ static void adpt_ia64_info(sysInfo_S* si)
}
#endif
-
#if defined __sparc__
static void adpt_sparc_info(sysInfo_S* si)
{
@@ -1857,7 +1986,6 @@ static void adpt_sparc_info(sysInfo_S* si)
si->processorType = PROC_ULTRASPARC;
}
#endif
-
#if defined __alpha__
static void adpt_alpha_info(sysInfo_S* si)
{
@@ -1869,7 +1997,6 @@ static void adpt_alpha_info(sysInfo_S* si)
#endif
#if defined __i386__
-
static void adpt_i386_info(sysInfo_S* si)
{
// This is all the info we need for now
@@ -1890,9 +2017,45 @@ static void adpt_i386_info(sysInfo_S* si)
break;
}
}
+#endif
+/*
+ * This routine returns information about the system. This does not effect
+ * any logic and if the info is wrong - it doesn't matter.
+ */
+
+/* Get all the info we can not get from kernel services */
+static int adpt_system_info(void __user *buffer)
+{
+ sysInfo_S si;
+
+ memset(&si, 0, sizeof(si));
+
+ si.osType = OS_LINUX;
+ si.osMajorVersion = 0;
+ si.osMinorVersion = 0;
+ si.osRevision = 0;
+ si.busType = SI_PCI_BUS;
+ si.processorFamily = DPTI_sig.dsProcessorFamily;
+
+#if defined __i386__
+ adpt_i386_info(&si);
+#elif defined (__ia64__)
+ adpt_ia64_info(&si);
+#elif defined(__sparc__)
+ adpt_sparc_info(&si);
+#elif defined (__alpha__)
+ adpt_alpha_info(&si);
+#else
+ si.processorType = 0xff ;
#endif
+ if (copy_to_user(buffer, &si, sizeof(si))){
+ printk(KERN_WARNING"dpti: Could not copy buffer TO user\n");
+ return -EFAULT;
+ }
+ return 0;
+}
static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
ulong arg)
@@ -1978,6 +2141,38 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
return error;
}
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode;
+ long ret;
+
+ inode = file->f_dentry->d_inode;
+
+ lock_kernel();
+
+ switch(cmd) {
+ case DPT_SIGNATURE:
+ case I2OUSRCMD:
+ case DPT_CTRLINFO:
+ case DPT_SYSINFO:
+ case DPT_BLINKLED:
+ case I2ORESETCMD:
+ case I2ORESCANCMD:
+ case (DPT_TARGET_BUSY & 0xFFFF):
+ case DPT_TARGET_BUSY:
+ ret = adpt_ioctl(inode, file, cmd, arg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ unlock_kernel();
+
+ return ret;
+}
+#endif
static irqreturn_t adpt_isr(int irq, void *dev_id)
{
@@ -2009,7 +2204,16 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
goto out;
}
}
- reply = bus_to_virt(m);
+ if (pHba->reply_pool_pa <= m &&
+ m < pHba->reply_pool_pa +
+ (pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) {
+ reply = (u8 *)pHba->reply_pool +
+ (m - pHba->reply_pool_pa);
+ } else {
+ /* Ick, we should *never* be here */
+ printk(KERN_ERR "dpti: reply frame not from pool\n");
+ reply = (u8 *)bus_to_virt(m);
+ }
if (readl(reply) & MSG_FAIL) {
u32 old_m = readl(reply+28);
@@ -2029,7 +2233,7 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
}
context = readl(reply+8);
if(context & 0x40000000){ // IOCTL
- void *p = (void *)readl(reply+12);
+ void *p = adpt_ioctl_from_context(pHba, readl(reply+12));
if( p != NULL) {
memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4);
}
@@ -2043,15 +2247,17 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
status = I2O_POST_WAIT_OK;
}
if(!(context & 0x40000000)) {
- cmd = (struct scsi_cmnd*) readl(reply+12);
+ cmd = adpt_cmd_from_context(pHba,
+ readl(reply+12));
if(cmd != NULL) {
printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
}
}
adpt_i2o_post_wait_complete(context, status);
} else { // SCSI message
- cmd = (struct scsi_cmnd*) readl(reply+12);
+ cmd = adpt_cmd_from_context (pHba, readl(reply+12));
if(cmd != NULL){
+ scsi_dma_unmap(cmd);
if(cmd->serial_number != 0) { // If not timedout
adpt_i2o_to_scsi(reply, cmd);
}
@@ -2072,6 +2278,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
int i;
u32 msg[MAX_MESSAGE_SIZE];
u32* mptr;
+ u32* lptr;
u32 *lenptr;
int direction;
int scsidir;
@@ -2079,6 +2286,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
u32 len;
u32 reqlen;
s32 rcode;
+ dma_addr_t addr;
memset(msg, 0 , sizeof(msg));
len = scsi_bufflen(cmd);
@@ -2118,7 +2326,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
// I2O_CMD_SCSI_EXEC
msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid);
msg[2] = 0;
- msg[3] = (u32)cmd; /* We want the SCSI control block back */
+ msg[3] = adpt_cmd_to_context(cmd); /* Want SCSI control block back */
// Our cards use the transaction context as the tag for queueing
// Adaptec/DPT Private stuff
msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16);
@@ -2136,7 +2344,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
memcpy(mptr, cmd->cmnd, cmd->cmd_len);
mptr+=4;
lenptr=mptr++; /* Remember me - fill in when we know */
- reqlen = 14; // SINGLE SGE
+ if (dpt_dma64(pHba)) {
+ reqlen = 16; // SINGLE SGE
+ *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+ *mptr++ = 1 << PAGE_SHIFT;
+ } else {
+ reqlen = 14; // SINGLE SGE
+ }
/* Now fill in the SGList and command */
nseg = scsi_dma_map(cmd);
@@ -2146,12 +2360,16 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
len = 0;
scsi_for_each_sg(cmd, sg, nseg, i) {
+ lptr = mptr;
*mptr++ = direction|0x10000000|sg_dma_len(sg);
len+=sg_dma_len(sg);
- *mptr++ = sg_dma_address(sg);
+ addr = sg_dma_address(sg);
+ *mptr++ = dma_low(addr);
+ if (dpt_dma64(pHba))
+ *mptr++ = dma_high(addr);
/* Make this an end of list */
if (i == nseg - 1)
- mptr[-2] = direction|0xD0000000|sg_dma_len(sg);
+ *lptr = direction|0xD0000000|sg_dma_len(sg);
}
reqlen = mptr - msg;
*lenptr = len;
@@ -2177,13 +2395,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
}
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht)
{
- struct Scsi_Host *host = NULL;
+ struct Scsi_Host *host;
- host = scsi_register(sht, sizeof(adpt_hba*));
+ host = scsi_host_alloc(sht, sizeof(adpt_hba*));
if (host == NULL) {
- printk ("%s: scsi_register returned NULL\n",pHba->name);
+ printk("%s: scsi_host_alloc returned NULL\n", pHba->name);
return -1;
}
host->hostdata[0] = (unsigned long)pHba;
@@ -2200,7 +2418,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
host->max_lun = 256;
host->max_channel = pHba->top_scsi_channel + 1;
host->cmd_per_lun = 1;
- host->unique_id = (uint) pHba;
+ host->unique_id = (u32)sys_tbl_pa + pHba->unit;
host->sg_tablesize = pHba->sg_tablesize;
host->can_queue = pHba->post_fifo_size;
@@ -2640,11 +2858,10 @@ static s32 adpt_send_nop(adpt_hba*pHba,u32 m)
static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
{
u8 *status;
+ dma_addr_t addr;
u32 __iomem *msg = NULL;
int i;
ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ;
- u32* ptr;
- u32 outbound_frame; // This had to be a 32 bit address
u32 m;
do {
@@ -2663,13 +2880,14 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
- status = kzalloc(4, GFP_KERNEL|ADDR32);
+ status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
if (!status) {
adpt_send_nop(pHba, m);
printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
pHba->name);
return -ENOMEM;
}
+ memset(status, 0, 4);
writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2678,7 +2896,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
writel(4096, &msg[4]); /* Host page frame size */
writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]); /* Outbound msg frame size and Initcode */
writel(0xD0000004, &msg[6]); /* Simple SG LE, EOB */
- writel(virt_to_bus(status), &msg[7]);
+ writel((u32)addr, &msg[7]);
writel(m, pHba->post_port);
wmb();
@@ -2693,6 +2911,10 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
rmb();
if(time_after(jiffies,timeout)){
printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
+ /* We lose 4 bytes of "status" here, but we
+ cannot free these because controller may
+ awake and corrupt those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -2701,25 +2923,30 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
// If the command was successful, fill the fifo with our reply
// message packets
if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) {
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
return -2;
}
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
- kfree(pHba->reply_pool);
+ if(pHba->reply_pool != NULL) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ pHba->reply_pool, pHba->reply_pool_pa);
+ }
- pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+ pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ &pHba->reply_pool_pa, GFP_KERNEL);
if (!pHba->reply_pool) {
printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
return -ENOMEM;
}
+ memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
- ptr = pHba->reply_pool;
for(i = 0; i < pHba->reply_fifo_size; i++) {
- outbound_frame = (u32)virt_to_bus(ptr);
- writel(outbound_frame, pHba->reply_port);
+ writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4),
+ pHba->reply_port);
wmb();
- ptr += REPLY_FRAME_SIZE;
}
adpt_i2o_status_get(pHba);
return 0;
@@ -2743,11 +2970,11 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
u32 m;
u32 __iomem *msg;
u8 *status_block=NULL;
- ulong status_block_bus;
if(pHba->status_block == NULL) {
- pHba->status_block = (i2o_status_block*)
- kmalloc(sizeof(i2o_status_block),GFP_KERNEL|ADDR32);
+ pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(i2o_status_block),
+ &pHba->status_block_pa, GFP_KERNEL);
if(pHba->status_block == NULL) {
printk(KERN_ERR
"dpti%d: Get Status Block failed; Out of memory. \n",
@@ -2757,7 +2984,6 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
}
memset(pHba->status_block, 0, sizeof(i2o_status_block));
status_block = (u8*)(pHba->status_block);
- status_block_bus = virt_to_bus(pHba->status_block);
timeout = jiffies+TMOUT_GETSTATUS*HZ;
do {
rmb();
@@ -2782,8 +3008,8 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
writel(0, &msg[3]);
writel(0, &msg[4]);
writel(0, &msg[5]);
- writel(((u32)status_block_bus)&0xffffffff, &msg[6]);
- writel(0, &msg[7]);
+ writel( dma_low(pHba->status_block_pa), &msg[6]);
+ writel( dma_high(pHba->status_block_pa), &msg[7]);
writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes
//post message
@@ -2812,7 +3038,17 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
}
// Calculate the Scatter Gather list size
- pHba->sg_tablesize = (pHba->status_block->inbound_frame_size * 4 -40)/ sizeof(struct sg_simple_element);
+ if (dpt_dma64(pHba)) {
+ pHba->sg_tablesize
+ = ((pHba->status_block->inbound_frame_size * 4
+ - 14 * sizeof(u32))
+ / (sizeof(struct sg_simple_element) + sizeof(u32)));
+ } else {
+ pHba->sg_tablesize
+ = ((pHba->status_block->inbound_frame_size * 4
+ - 12 * sizeof(u32))
+ / sizeof(struct sg_simple_element));
+ }
if (pHba->sg_tablesize > SG_LIST_ELEMENTS) {
pHba->sg_tablesize = SG_LIST_ELEMENTS;
}
@@ -2863,7 +3099,9 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
}
do {
if (pHba->lct == NULL) {
- pHba->lct = kmalloc(pHba->lct_size, GFP_KERNEL|ADDR32);
+ pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
+ pHba->lct_size, &pHba->lct_pa,
+ GFP_KERNEL);
if(pHba->lct == NULL) {
printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
pHba->name);
@@ -2879,7 +3117,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
msg[4] = 0xFFFFFFFF; /* All devices */
msg[5] = 0x00000000; /* Report now */
msg[6] = 0xD0000000|pHba->lct_size;
- msg[7] = virt_to_bus(pHba->lct);
+ msg[7] = (u32)pHba->lct_pa;
if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) {
printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n",
@@ -2890,7 +3128,8 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
if ((pHba->lct->table_size << 2) > pHba->lct_size) {
pHba->lct_size = pHba->lct->table_size << 2;
- kfree(pHba->lct);
+ dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+ pHba->lct, pHba->lct_pa);
pHba->lct = NULL;
}
} while (pHba->lct == NULL);
@@ -2901,13 +3140,19 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
// I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) {
pHba->FwDebugBufferSize = buf[1];
- pHba->FwDebugBuffer_P = pHba->base_addr_virt + buf[0];
- pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P + FW_DEBUG_FLAGS_OFFSET;
- pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + FW_DEBUG_BLED_OFFSET;
- pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1;
- pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + FW_DEBUG_STR_LENGTH_OFFSET;
- pHba->FwDebugBuffer_P += buf[2];
- pHba->FwDebugFlags = 0;
+ pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0],
+ pHba->FwDebugBufferSize);
+ if (pHba->FwDebugBuffer_P) {
+ pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_FLAGS_OFFSET;
+ pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_BLED_OFFSET;
+ pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1;
+ pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_STR_LENGTH_OFFSET;
+ pHba->FwDebugBuffer_P += buf[2];
+ pHba->FwDebugFlags = 0;
+ }
}
return 0;
@@ -2915,25 +3160,30 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
static int adpt_i2o_build_sys_table(void)
{
- adpt_hba* pHba = NULL;
+ adpt_hba* pHba = hba_chain;
int count = 0;
+ if (sys_tbl)
+ dma_free_coherent(&pHba->pDev->dev, sys_tbl_len,
+ sys_tbl, sys_tbl_pa);
+
sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs
(hba_count) * sizeof(struct i2o_sys_tbl_entry);
- kfree(sys_tbl);
-
- sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+ sys_tbl = dma_alloc_coherent(&pHba->pDev->dev,
+ sys_tbl_len, &sys_tbl_pa, GFP_KERNEL);
if (!sys_tbl) {
printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");
return -ENOMEM;
}
+ memset(sys_tbl, 0, sys_tbl_len);
sys_tbl->num_entries = hba_count;
sys_tbl->version = I2OVERSION;
sys_tbl->change_ind = sys_tbl_ind++;
for(pHba = hba_chain; pHba; pHba = pHba->next) {
+ u64 addr;
// Get updated Status Block so we have the latest information
if (adpt_i2o_status_get(pHba)) {
sys_tbl->num_entries--;
@@ -2949,8 +3199,9 @@ static int adpt_i2o_build_sys_table(void)
sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size;
sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities;
- sys_tbl->iops[count].inbound_low = (u32)virt_to_bus(pHba->post_port);
- sys_tbl->iops[count].inbound_high = (u32)((u64)virt_to_bus(pHba->post_port)>>32);
+ addr = pHba->base_addr_phys + 0x40;
+ sys_tbl->iops[count].inbound_low = dma_low(addr);
+ sys_tbl->iops[count].inbound_high = dma_high(addr);
count++;
}
@@ -3086,7 +3337,8 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
do {
if (pHba->hrt == NULL) {
- pHba->hrt=kmalloc(size, GFP_KERNEL|ADDR32);
+ pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev,
+ size, &pHba->hrt_pa, GFP_KERNEL);
if (pHba->hrt == NULL) {
printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name);
return -ENOMEM;
@@ -3098,7 +3350,7 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
msg[2]= 0;
msg[3]= 0;
msg[4]= (0xD0000000 | size); /* Simple transaction */
- msg[5]= virt_to_bus(pHba->hrt); /* Dump it here */
+ msg[5]= (u32)pHba->hrt_pa; /* Dump it here */
if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) {
printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret);
@@ -3106,8 +3358,10 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
}
if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) {
- size = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
- kfree(pHba->hrt);
+ int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
+ dma_free_coherent(&pHba->pDev->dev, size,
+ pHba->hrt, pHba->hrt_pa);
+ size = newsize;
pHba->hrt = NULL;
}
} while(pHba->hrt == NULL);
@@ -3121,33 +3375,54 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
int group, int field, void *buf, int buflen)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
- u8 *resblk;
+ u8 *opblk_va;
+ dma_addr_t opblk_pa;
+ u8 *resblk_va;
+ dma_addr_t resblk_pa;
int size;
/* 8 bytes for header */
- resblk = kmalloc(sizeof(u8) * (8+buflen), GFP_KERNEL|ADDR32);
- if (resblk == NULL) {
+ resblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL);
+ if (resblk_va == NULL) {
printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
return -ENOMEM;
}
+ opblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(opblk), &opblk_pa, GFP_KERNEL);
+ if (opblk_va == NULL) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
+ printk(KERN_CRIT "%s: query operatio failed; Out of memory.\n",
+ pHba->name);
+ return -ENOMEM;
+ }
if (field == -1) /* whole group */
opblk[4] = -1;
+ memcpy(opblk_va, opblk, sizeof(opblk));
size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid,
- opblk, sizeof(opblk), resblk, sizeof(u8)*(8+buflen));
+ opblk_va, opblk_pa, sizeof(opblk),
+ resblk_va, resblk_pa, sizeof(u8)*(8+buflen));
+ dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa);
if (size == -ETIME) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
return -ETIME;
} else if (size == -EINTR) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
return -EINTR;
}
- memcpy(buf, resblk+8, buflen); /* cut off header */
+ memcpy(buf, resblk_va+8, buflen); /* cut off header */
- kfree(resblk);
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
if (size < 0)
return size;
@@ -3164,10 +3439,11 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
* ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
*/
static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
- void *opblk, int oplen, void *resblk, int reslen)
+ void *opblk_va, dma_addr_t opblk_pa, int oplen,
+ void *resblk_va, dma_addr_t resblk_pa, int reslen)
{
u32 msg[9];
- u32 *res = (u32 *)resblk;
+ u32 *res = (u32 *)resblk_va;
int wait_status;
msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
@@ -3176,12 +3452,12 @@ static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
msg[3] = 0;
msg[4] = 0;
msg[5] = 0x54000000 | oplen; /* OperationBlock */
- msg[6] = virt_to_bus(opblk);
+ msg[6] = (u32)opblk_pa;
msg[7] = 0xD0000000 | reslen; /* ResultBlock */
- msg[8] = virt_to_bus(resblk);
+ msg[8] = (u32)resblk_pa;
if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
- printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk);
+ printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va);
return wait_status; /* -DetailedStatus */
}
@@ -3284,7 +3560,7 @@ static int adpt_i2o_systab_send(adpt_hba* pHba)
* Private i/o space declaration
*/
msg[6] = 0x54000000 | sys_tbl_len;
- msg[7] = virt_to_phys(sys_tbl);
+ msg[7] = (u32)sys_tbl_pa;
msg[8] = 0x54000000 | 0;
msg[9] = 0;
msg[10] = 0xD4000000 | 0;
@@ -3323,11 +3599,10 @@ static static void adpt_delay(int millisec)
#endif
static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
.name = "dpt_i2o",
.proc_name = "dpt_i2o",
.proc_info = adpt_proc_info,
- .detect = adpt_detect,
- .release = adpt_release,
.info = adpt_info,
.queuecommand = adpt_queue,
.eh_abort_handler = adpt_abort,
@@ -3341,5 +3616,48 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
};
-#include "scsi_module.c"
+
+static int __init adpt_init(void)
+{
+ int error;
+ adpt_hba *pHba, *next;
+
+ printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+
+ error = adpt_detect(&driver_template);
+ if (error < 0)
+ return error;
+ if (hba_chain == NULL)
+ return -ENODEV;
+
+ for (pHba = hba_chain; pHba; pHba = pHba->next) {
+ error = scsi_add_host(pHba->host, &pHba->pDev->dev);
+ if (error)
+ goto fail;
+ scsi_scan_host(pHba->host);
+ }
+ return 0;
+fail:
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
+ scsi_remove_host(pHba->host);
+ }
+ return error;
+}
+
+static void __exit adpt_exit(void)
+{
+ adpt_hba *pHba, *next;
+
+ for (pHba = hba_chain; pHba; pHba = pHba->next)
+ scsi_remove_host(pHba->host);
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
+ adpt_release(pHba->host);
+ }
+}
+
+module_init(adpt_init);
+module_exit(adpt_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index fd79068c5869..337746d46043 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -84,7 +84,6 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
#define PCI_DPT_DEVICE_ID (0xA501) // DPT PCI I2O Device ID
#define PCI_DPT_RAPTOR_DEVICE_ID (0xA511)
-//#define REBOOT_NOTIFIER 1
/* Debugging macro from Linux Device Drivers - Rubini */
#undef PDEBUG
#ifdef DEBUG
@@ -229,14 +228,19 @@ typedef struct _adpt_hba {
u32 post_fifo_size;
u32 reply_fifo_size;
u32* reply_pool;
+ dma_addr_t reply_pool_pa;
u32 sg_tablesize; // Scatter/Gather List Size.
u8 top_scsi_channel;
u8 top_scsi_id;
u8 top_scsi_lun;
+ u8 dma64;
i2o_status_block* status_block;
+ dma_addr_t status_block_pa;
i2o_hrt* hrt;
+ dma_addr_t hrt_pa;
i2o_lct* lct;
+ dma_addr_t lct_pa;
uint lct_size;
struct i2o_device* devices;
struct adpt_channel channel[MAX_CHANNEL];
@@ -249,6 +253,7 @@ typedef struct _adpt_hba {
void __iomem *FwDebugBLEDflag_P;// Virtual Addr Of FW Debug BLED
void __iomem *FwDebugBLEDvalue_P;// Virtual Addr Of FW Debug BLED
u32 FwDebugFlags;
+ u32 *ioctl_reply_context[4];
} adpt_hba;
struct sg_simple_element {
@@ -264,9 +269,6 @@ static void adpt_i2o_sys_shutdown(void);
static int adpt_init(void);
static int adpt_i2o_build_sys_table(void);
static irqreturn_t adpt_isr(int irq, void *dev_id);
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
-#endif
static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d);
static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
@@ -275,7 +277,8 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
static const char *adpt_i2o_get_class_name(int class);
#endif
static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
- void *opblk, int oplen, void *resblk, int reslen);
+ void *opblk, dma_addr_t opblk_pa, int oplen,
+ void *resblk, dma_addr_t resblk_pa, int reslen);
static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout);
static int adpt_i2o_lct_get(adpt_hba* pHba);
static int adpt_i2o_parse_lct(adpt_hba* pHba);
@@ -289,7 +292,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba);
static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd);
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba,struct scsi_host_template * sht);
static s32 adpt_hba_reset(adpt_hba* pHba);
static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
static s32 adpt_rescan(adpt_hba* pHba);
@@ -313,19 +316,6 @@ static int adpt_close(struct inode *inode, struct file *file);
static void adpt_delay(int millisec);
#endif
-#if defined __ia64__
-static void adpt_ia64_info(sysInfo_S* si);
-#endif
-#if defined __sparc__
-static void adpt_sparc_info(sysInfo_S* si);
-#endif
-#if defined __alpha__
-static void adpt_sparc_info(sysInfo_S* si);
-#endif
-#if defined __i386__
-static void adpt_i386_info(sysInfo_S* si);
-#endif
-
#define PRINT_BUFFER_SIZE 512
#define HBA_FLAGS_DBG_FLAGS_MASK 0xffff0000 // Mask for debug flags
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index c6d6e7c6559a..46771d4c81bd 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -465,7 +465,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
scp->request = (struct request *)&wait;
scp->timeout_per_command = timeout*HZ;
scp->cmd_len = 12;
- memcpy(scp->cmnd, cmnd, 12);
+ scp->cmnd = cmnd;
cmndinfo.priority = IOCTL_PRI;
cmndinfo.internal_cmd_str = gdtcmd;
cmndinfo.internal_command = 1;
@@ -550,7 +550,6 @@ static int __init gdth_search_isa(ulong32 bios_adr)
#endif /* CONFIG_ISA */
#ifdef CONFIG_PCI
-static bool gdth_pci_registered;
static bool gdth_search_vortex(ushort device)
{
@@ -3724,6 +3723,8 @@ static void gdth_log_event(gdth_evt_data *dvr, char *buffer)
}
#ifdef GDTH_STATISTICS
+static unchar gdth_timer_running;
+
static void gdth_timeout(ulong data)
{
ulong32 i;
@@ -3731,7 +3732,10 @@ static void gdth_timeout(ulong data)
gdth_ha_str *ha;
ulong flags;
- BUG_ON(list_empty(&gdth_instances));
+ if(unlikely(list_empty(&gdth_instances))) {
+ gdth_timer_running = 0;
+ return;
+ }
ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -3751,6 +3755,22 @@ static void gdth_timeout(ulong data)
add_timer(&gdth_timer);
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
+
+static void gdth_timer_init(void)
+{
+ if (gdth_timer_running)
+ return;
+ gdth_timer_running = 1;
+ TRACE2(("gdth_detect(): Initializing timer !\n"));
+ gdth_timer.expires = jiffies + HZ;
+ gdth_timer.data = 0L;
+ gdth_timer.function = gdth_timeout;
+ add_timer(&gdth_timer);
+}
+#else
+static inline void gdth_timer_init(void)
+{
+}
#endif
static void __init internal_setup(char *str,int *ints)
@@ -4735,6 +4755,7 @@ static int __init gdth_isa_probe_one(ulong32 isa_bios)
if (error)
goto out_free_coal_stat;
list_add_tail(&ha->list, &gdth_instances);
+ gdth_timer_init();
scsi_scan_host(shp);
@@ -4865,6 +4886,7 @@ static int __init gdth_eisa_probe_one(ushort eisa_slot)
if (error)
goto out_free_coal_stat;
list_add_tail(&ha->list, &gdth_instances);
+ gdth_timer_init();
scsi_scan_host(shp);
@@ -5011,6 +5033,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr,
list_add_tail(&ha->list, &gdth_instances);
pci_set_drvdata(ha->pdev, ha);
+ gdth_timer_init();
scsi_scan_host(shp);
@@ -5110,6 +5133,7 @@ static int __init gdth_init(void)
/* initializations */
gdth_polling = TRUE;
gdth_clear_events();
+ init_timer(&gdth_timer);
/* As default we do not probe for EISA or ISA controllers */
if (probe_eisa_isa) {
@@ -5132,23 +5156,17 @@ static int __init gdth_init(void)
#ifdef CONFIG_PCI
/* scanning for PCI controllers */
- if (pci_register_driver(&gdth_pci_driver) == 0)
- gdth_pci_registered = true;
+ if (pci_register_driver(&gdth_pci_driver)) {
+ gdth_ha_str *ha;
+
+ list_for_each_entry(ha, &gdth_instances, list)
+ gdth_remove_one(ha);
+ return -ENODEV;
+ }
#endif /* CONFIG_PCI */
TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count));
- if (list_empty(&gdth_instances))
- return -ENODEV;
-
-#ifdef GDTH_STATISTICS
- TRACE2(("gdth_detect(): Initializing timer !\n"));
- init_timer(&gdth_timer);
- gdth_timer.expires = jiffies + HZ;
- gdth_timer.data = 0L;
- gdth_timer.function = gdth_timeout;
- add_timer(&gdth_timer);
-#endif
major = register_chrdev(0,"gdth", &gdth_fops);
register_reboot_notifier(&gdth_notifier);
gdth_polling = FALSE;
@@ -5167,8 +5185,7 @@ static void __exit gdth_exit(void)
#endif
#ifdef CONFIG_PCI
- if (gdth_pci_registered)
- pci_unregister_driver(&gdth_pci_driver);
+ pci_unregister_driver(&gdth_pci_driver);
#endif
list_for_each_entry(ha, &gdth_instances, list)
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 5b7be1e9841c..aaa48e0c8ed0 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -763,9 +763,9 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
scp,
host->host_no, scp->device->channel,
scp->device->id, scp->device->lun,
- *((u32 *)&scp->cmnd),
- *((u32 *)&scp->cmnd + 1),
- *((u32 *)&scp->cmnd + 2),
+ ((u32 *)scp->cmnd)[0],
+ ((u32 *)scp->cmnd)[1],
+ ((u32 *)scp->cmnd)[2],
_req->index, _req->req_virt);
scp->result = 0;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 4a922c57125e..ccfd8aca3765 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -686,7 +686,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
}
if (cmnd) {
- cmnd->result = rsp->status;
+ cmnd->result |= rsp->status;
if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
memcpy(cmnd->sense_buffer,
rsp->data,
@@ -730,6 +730,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
u16 lun = lun_from_dev(cmnd->device);
u8 out_fmt, in_fmt;
+ cmnd->result = (DID_OK << 16);
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -738,7 +739,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
srp_cmd->opcode = SRP_CMD;
- memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+ memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
@@ -1347,6 +1348,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
del_timer(&evt_struct->timer);
+ if (crq->status != VIOSRP_OK && evt_struct->cmnd)
+ evt_struct->cmnd->result = DID_ERROR << 16;
if (evt_struct->done)
evt_struct->done(evt_struct);
else
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 90f1a61283ad..4c4aadb3e405 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -59,6 +59,15 @@ enum viosrp_crq_formats {
VIOSRP_INLINE_FORMAT = 0x07
};
+enum viosrp_crq_status {
+ VIOSRP_OK = 0x0,
+ VIOSRP_NONRECOVERABLE_ERR = 0x1,
+ VIOSRP_VIOLATES_MAX_XFER = 0x2,
+ VIOSRP_PARTNER_PANIC = 0x3,
+ VIOSRP_DEVICE_BUSY = 0x8,
+ VIOSRP_ADAPTER_FAIL = 0x10
+};
+
struct viosrp_crq {
u8 valid; /* used by RPA */
u8 format; /* SCSI vs out-of-band */
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index dbae3fdb8506..e3f739776bad 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2590,7 +2590,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
cblk->hastat = 0;
cblk->tastat = 0;
/* Command the command */
- memcpy(&cblk->cdb[0], &cmnd->cmnd, cmnd->cmd_len);
+ memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len);
/* Set up tags */
if (cmnd->device->tagged_supported) { /* Tag Support */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index de5ae6a65029..999e91ea7451 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -2791,7 +2791,7 @@ static ssize_t ipr_store_adapter_state(struct device *dev,
static struct device_attribute ipr_ioa_state_attr = {
.attr = {
- .name = "state",
+ .name = "online_state",
.mode = S_IRUGO | S_IWUSR,
},
.show = ipr_show_adapter_state,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 010c1b9b178c..b43bf1d60dac 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -730,7 +730,9 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
datalen))
rc = ISCSI_ERR_CONN_FAILED;
- }
+ } else
+ mod_timer(&conn->transport_timer,
+ jiffies + conn->recv_timeout);
iscsi_free_mgmt_task(conn, mtask);
break;
default:
@@ -1453,19 +1455,20 @@ static void iscsi_check_transport_timeouts(unsigned long data)
{
struct iscsi_conn *conn = (struct iscsi_conn *)data;
struct iscsi_session *session = conn->session;
- unsigned long timeout, next_timeout = 0, last_recv;
+ unsigned long recv_timeout, next_timeout = 0, last_recv;
spin_lock(&session->lock);
if (session->state != ISCSI_STATE_LOGGED_IN)
goto done;
- timeout = conn->recv_timeout;
- if (!timeout)
+ recv_timeout = conn->recv_timeout;
+ if (!recv_timeout)
goto done;
- timeout *= HZ;
+ recv_timeout *= HZ;
last_recv = conn->last_recv;
- if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
+ if (conn->ping_mtask &&
+ time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
jiffies)) {
iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
"expired, last rx %lu, last ping %lu, "
@@ -1476,15 +1479,13 @@ static void iscsi_check_transport_timeouts(unsigned long data)
return;
}
- if (time_before_eq(last_recv + timeout, jiffies)) {
- if (time_before_eq(conn->last_ping, last_recv)) {
- /* send a ping to try to provoke some traffic */
- debug_scsi("Sending nopout as ping on conn %p\n", conn);
- iscsi_send_nopout(conn, NULL);
- }
- next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
+ if (time_before_eq(last_recv + recv_timeout, jiffies)) {
+ /* send a ping to try to provoke some traffic */
+ debug_scsi("Sending nopout as ping on conn %p\n", conn);
+ iscsi_send_nopout(conn, NULL);
+ next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
} else
- next_timeout = last_recv + timeout;
+ next_timeout = last_recv + recv_timeout;
debug_scsi("Setting next tmo %lu\n", next_timeout);
mod_timer(&conn->transport_timer, next_timeout);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index b135a1ed4b2c..18551aaf5e09 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4996,7 +4996,7 @@ static int __init megaraid_init(void)
max_mbox_busy_wait = MBOX_BUSY_WAIT;
#ifdef CONFIG_PROC_FS
- mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+ mega_proc_dir_entry = proc_mkdir("megaraid", NULL);
if (!mega_proc_dir_entry) {
printk(KERN_WARNING
"megaraid: failed to create megaraid root\n");
@@ -5005,7 +5005,7 @@ static int __init megaraid_init(void)
error = pci_register_driver(&megaraid_pci_driver);
if (error) {
#ifdef CONFIG_PROC_FS
- remove_proc_entry("megaraid", &proc_root);
+ remove_proc_entry("megaraid", NULL);
#endif
return error;
}
@@ -5035,7 +5035,7 @@ static void __exit megaraid_exit(void)
pci_unregister_driver(&megaraid_pci_driver);
#ifdef CONFIG_PROC_FS
- remove_proc_entry("megaraid", &proc_root);
+ remove_proc_entry("megaraid", NULL);
#endif
}
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 820f91fb63ba..70a0f11f48b2 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -3168,6 +3168,23 @@ megaraid_mbox_support_random_del(adapter_t *adapter)
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
+ /*
+ * Newer firmware on Dell CERC expect a different
+ * random deletion handling, so disable it.
+ */
+ if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI &&
+ adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 &&
+ adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH &&
+ (adapter->fw_version[0] > '6' ||
+ (adapter->fw_version[0] == '6' &&
+ adapter->fw_version[2] > '6') ||
+ (adapter->fw_version[0] == '6'
+ && adapter->fw_version[2] == '6'
+ && adapter->fw_version[3] > '1'))) {
+ con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n"));
+ return 0;
+ }
mbox = (mbox_t *)raw_mbox;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 626459d1e902..c1d86d961a92 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -88,6 +88,7 @@
#define PCI_SUBSYS_ID_PERC3_QC 0x0471
#define PCI_SUBSYS_ID_PERC3_DC 0x0493
#define PCI_SUBSYS_ID_PERC3_SC 0x0475
+#define PCI_SUBSYS_ID_CERC_ATA100_4CH 0x0511
#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index b937e9cddb23..7d84c8bbcf3f 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.16-rc1
+ * Version : v00.00.03.20-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -2650,12 +2650,13 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
return;
}
+#ifdef CONFIG_PM
/**
* megasas_suspend - driver suspend entry point
* @pdev: PCI device structure
* @state: PCI power state to suspend routine
*/
-static int __devinit
+static int
megasas_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *host;
@@ -2687,7 +2688,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
* megasas_resume- driver resume entry point
* @pdev: PCI device structure
*/
-static int __devinit
+static int
megasas_resume(struct pci_dev *pdev)
{
int rval;
@@ -2782,12 +2783,16 @@ fail_ready_state:
return -ENODEV;
}
+#else
+#define megasas_suspend NULL
+#define megasas_resume NULL
+#endif
/**
* megasas_detach_one - PCI hot"un"plug entry point
* @pdev: PCI device structure
*/
-static void megasas_detach_one(struct pci_dev *pdev)
+static void __devexit megasas_detach_one(struct pci_dev *pdev)
{
int i;
struct Scsi_Host *host;
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 3a997eb457bf..b0c41e671702 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.03.16-rc1"
-#define MEGASAS_RELDATE "Nov. 07, 2007"
-#define MEGASAS_EXT_VERSION "Thu. Nov. 07 10:09:32 PDT 2007"
+#define MEGASAS_VERSION "00.00.03.20-rc1"
+#define MEGASAS_RELDATE "March 10, 2008"
+#define MEGASAS_EXT_VERSION "Mon. March 10 11:02:31 PDT 2008"
/*
* Device IDs
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index e55b9037adb2..1dd70d7a4947 100644
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2822,7 +2822,9 @@ static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
dev_printk(KERN_DEBUG, &pdev->dev,
"phy[%d] Get Attached Address 0x%llX ,"
" SAS Address 0x%llX\n",
- i, phy->att_dev_sas_addr, phy->dev_sas_addr);
+ i,
+ (unsigned long long)phy->att_dev_sas_addr,
+ (unsigned long long)phy->dev_sas_addr);
dev_printk(KERN_DEBUG, &pdev->dev,
"Rate = %x , type = %d\n",
sas_phy->linkrate, phy->phy_type);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index ceab4f73caf1..c57c94c0ffd2 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8222,7 +8222,7 @@ static void process_waiting_list(struct ncb *np, int sts)
#ifdef DEBUG_WAITING_LIST
if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
#endif
- while (wcmd = waiting_list) {
+ while ((wcmd = waiting_list) != NULL) {
waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd;
wcmd->next_wcmd = NULL;
if (sts == DID_OK) {
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 09ab3eac1c1a..51e2f299dbbb 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2007,7 +2007,7 @@ qla1280_set_defaults(struct scsi_qla_host *ha)
nv->bus[bus].config_2.req_ack_active_negation = 1;
nv->bus[bus].config_2.data_line_active_negation = 1;
nv->bus[bus].selection_timeout = 250;
- nv->bus[bus].max_queue_depth = 256;
+ nv->bus[bus].max_queue_depth = 32;
if (IS_ISP1040(ha)) {
nv->bus[bus].bus_reset_delay = 3;
@@ -2051,7 +2051,7 @@ qla1280_config_target(struct scsi_qla_host *ha, int bus, int target)
status = qla1280_mailbox_command(ha, 0x0f, mb);
/* Save Tag queuing enable flag. */
- flag = (BIT_0 << target) & mb[0];
+ flag = (BIT_0 << target);
if (nv->bus[bus].target[target].parameter.tag_queuing)
ha->bus_settings[bus].qtag_enables |= flag;
@@ -2858,7 +2858,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
/* Load SCSI command packet. */
pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
- memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+ memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
/* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
/* Set transfer direction. */
@@ -3127,7 +3127,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
/* Load SCSI command packet. */
pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
- memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+ memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
/*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
/* Set transfer direction. */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 12d69d7c8577..110e776d1a07 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -79,15 +79,6 @@ static void scsi_done(struct scsi_cmnd *cmd);
#define MIN_RESET_PERIOD (15*HZ)
/*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd) (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
- COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
-/*
* Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface.
*/
@@ -469,6 +460,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
if (!cmd) {
scsi_put_host_cmd_pool(gfp_mask);
+ shost->cmd_pool = NULL;
return -ENOMEM;
}
list_add(&cmd->list, &shost->free_list);
@@ -481,6 +473,13 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
*/
void scsi_destroy_command_freelist(struct Scsi_Host *shost)
{
+ /*
+ * If cmd_pool is NULL the free list was not initialized, so
+ * do not attempt to release resources.
+ */
+ if (!shost->cmd_pool)
+ return;
+
while (!list_empty(&shost->free_list)) {
struct scsi_cmnd *cmd;
@@ -701,9 +700,11 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
* Before we queue this command, check if the command
* length exceeds what the host adapter can handle.
*/
- if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
+ if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
SCSI_LOG_MLQUEUE(3,
- printk("queuecommand : command too long.\n"));
+ printk("queuecommand : command too long. "
+ "cdb_size=%d host->max_cmd_len=%d\n",
+ cmd->cmd_len, cmd->device->host->max_cmd_len));
cmd->result = (DID_ABORT << 16);
scsi_done(cmd);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 07103c399fe0..f6600bfb5bde 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1773,7 +1773,7 @@ static int scsi_debug_slave_alloc(struct scsi_device *sdp)
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
- set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
+ queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
return 0;
}
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index b8de041bc0ae..a235802f2981 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -449,37 +449,40 @@ int scsi_get_device_flags(struct scsi_device *sdev,
}
#ifdef CONFIG_SCSI_PROC_FS
-/*
- * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
- * /proc/scsi/device_info
- */
-static int proc_scsi_devinfo_read(char *buffer, char **start,
- off_t offset, int length)
+static int devinfo_seq_show(struct seq_file *m, void *v)
{
- struct scsi_dev_info_list *devinfo;
- int size, len = 0;
- off_t begin = 0;
- off_t pos = 0;
+ struct scsi_dev_info_list *devinfo =
+ list_entry(v, struct scsi_dev_info_list, dev_info_list);
- list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
- size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
+ seq_printf(m, "'%.8s' '%.16s' 0x%x\n",
devinfo->vendor, devinfo->model, devinfo->flags);
- len += size;
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
+ return 0;
+}
+
+static void * devinfo_seq_start(struct seq_file *m, loff_t *pos)
+{
+ return seq_list_start(&scsi_dev_info_list, *pos);
+}
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
+static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ return seq_list_next(v, &scsi_dev_info_list, pos);
+}
+
+static void devinfo_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static const struct seq_operations scsi_devinfo_seq_ops = {
+ .start = devinfo_seq_start,
+ .next = devinfo_seq_next,
+ .stop = devinfo_seq_stop,
+ .show = devinfo_seq_show,
+};
+
+static int proc_scsi_devinfo_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_devinfo_seq_ops);
}
/*
@@ -489,11 +492,12 @@ stop_output:
* integer value of flag to the scsi device info list.
* To use, echo "vendor:model:flag" > /proc/scsi/device_info
*/
-static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
- unsigned long length, void *data)
+static ssize_t proc_scsi_devinfo_write(struct file *file,
+ const char __user *buf,
+ size_t length, loff_t *ppos)
{
char *buffer;
- int err = length;
+ ssize_t err = length;
if (!buf || length>PAGE_SIZE)
return -EINVAL;
@@ -517,6 +521,15 @@ out:
free_page((unsigned long)buffer);
return err;
}
+
+static const struct file_operations scsi_devinfo_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_scsi_devinfo_open,
+ .read = seq_read,
+ .write = proc_scsi_devinfo_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
#endif /* CONFIG_SCSI_PROC_FS */
module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0);
@@ -577,15 +590,13 @@ int __init scsi_init_devinfo(void)
}
#ifdef CONFIG_SCSI_PROC_FS
- p = create_proc_entry("scsi/device_info", 0, NULL);
+ p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops);
if (!p) {
error = -ENOMEM;
goto out;
}
p->owner = THIS_MODULE;
- p->get_info = proc_scsi_devinfo_read;
- p->write_proc = proc_scsi_devinfo_write;
#endif /* CONFIG_SCSI_PROC_FS */
out:
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 221f31e36d26..eaf5a8add1ba 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -626,7 +626,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
* @scmd: SCSI command structure to hijack
* @ses: structure to save restore information
* @cmnd: CDB to send. Can be NULL if no new cmnd is needed
- * @cmnd_size: size in bytes of @cmnd
+ * @cmnd_size: size in bytes of @cmnd (must be <= BLK_MAX_CDB)
* @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
*
* This function is used to save a scsi command information before re-execution
@@ -648,12 +648,14 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
* command.
*/
ses->cmd_len = scmd->cmd_len;
- memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ ses->cmnd = scmd->cmnd;
ses->data_direction = scmd->sc_data_direction;
ses->sdb = scmd->sdb;
ses->next_rq = scmd->request->next_rq;
ses->result = scmd->result;
+ scmd->cmnd = ses->eh_cmnd;
+ memset(scmd->cmnd, 0, BLK_MAX_CDB);
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
scmd->request->next_rq = NULL;
@@ -665,14 +667,13 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
scmd->sdb.table.sgl = &ses->sense_sgl;
scmd->sc_data_direction = DMA_FROM_DEVICE;
scmd->sdb.table.nents = 1;
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
scmd->cmnd[0] = REQUEST_SENSE;
scmd->cmnd[4] = scmd->sdb.length;
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
} else {
scmd->sc_data_direction = DMA_NONE;
if (cmnd) {
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ BUG_ON(cmnd_size > BLK_MAX_CDB);
memcpy(scmd->cmnd, cmnd, cmnd_size);
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
}
@@ -705,7 +706,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
* Restore original data
*/
scmd->cmd_len = ses->cmd_len;
- memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+ scmd->cmnd = ses->cmnd;
scmd->sc_data_direction = ses->data_direction;
scmd->sdb = ses->sdb;
scmd->request->next_rq = ses->next_rq;
@@ -1771,11 +1772,12 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
unsigned long flags;
int rtn;
+ blk_rq_init(NULL, &req);
scmd->request = &req;
memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
- memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
-
+ scmd->cmnd = req.cmd;
+
scmd->scsi_done = scsi_reset_provider_done_command;
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 67f412bb4974..a82d2fe80fb5 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -445,7 +445,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
scsi_set_resid(cmd, 0);
memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
if (cmd->cmd_len == 0)
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+ cmd->cmd_len = scsi_command_size(cmd->cmnd);
}
void scsi_device_unbusy(struct scsi_device *sdev)
@@ -536,6 +536,9 @@ static void scsi_run_queue(struct request_queue *q)
!shost->host_blocked && !shost->host_self_blocked &&
!((shost->can_queue > 0) &&
(shost->host_busy >= shost->can_queue))) {
+
+ int flagset;
+
/*
* As long as shost is accepting commands and we have
* starved queues, call blk_run_queue. scsi_request_fn
@@ -549,19 +552,20 @@ static void scsi_run_queue(struct request_queue *q)
sdev = list_entry(shost->starved_list.next,
struct scsi_device, starved_entry);
list_del_init(&sdev->starved_entry);
- spin_unlock_irqrestore(shost->host_lock, flags);
-
+ spin_unlock(shost->host_lock);
+
+ spin_lock(sdev->request_queue->queue_lock);
+ flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
+ !test_bit(QUEUE_FLAG_REENTER,
+ &sdev->request_queue->queue_flags);
+ if (flagset)
+ queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue);
+ __blk_run_queue(sdev->request_queue);
+ if (flagset)
+ queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue);
+ spin_unlock(sdev->request_queue->queue_lock);
- if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
- !test_and_set_bit(QUEUE_FLAG_REENTER,
- &sdev->request_queue->queue_flags)) {
- blk_run_queue(sdev->request_queue);
- clear_bit(QUEUE_FLAG_REENTER,
- &sdev->request_queue->queue_flags);
- } else
- blk_run_queue(sdev->request_queue);
-
- spin_lock_irqsave(shost->host_lock, flags);
+ spin_lock(shost->host_lock);
if (unlikely(!list_empty(&sdev->starved_entry)))
/*
* sdev lost a race, and was put back on the
@@ -1090,6 +1094,8 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
cmd->tag = req->tag;
cmd->request = req;
+ cmd->cmnd = req->cmd;
+
return cmd;
}
@@ -1127,8 +1133,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
req->buffer = NULL;
}
- BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
- memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
cmd->cmd_len = req->cmd_len;
if (!req->data_len)
cmd->sc_data_direction = DMA_NONE;
@@ -1165,6 +1169,7 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;
+ memset(cmd->cmnd, 0, BLK_MAX_CDB);
return scsi_init_io(cmd, GFP_ATOMIC);
}
EXPORT_SYMBOL(scsi_setup_fs_cmnd);
@@ -1585,8 +1590,9 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
blk_queue_max_segment_size(q, dma_get_max_seg_size(dev));
+ /* New queue, no concurrency on queue_flags */
if (!shost->use_clustering)
- clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+ queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
/*
* set a reasonable default alignment on word boundaries: the
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 3a1c99d5c775..e4a0d2f9b357 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -413,6 +413,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_scsi_operations = {
+ .owner = THIS_MODULE,
.open = proc_scsi_open,
.read = seq_read,
.write = proc_scsi_write,
@@ -431,10 +432,9 @@ int __init scsi_init_procfs(void)
if (!proc_scsi)
goto err1;
- pde = create_proc_entry("scsi/scsi", 0, NULL);
+ pde = proc_create("scsi/scsi", 0, NULL, &proc_scsi_operations);
if (!pde)
goto err2;
- pde->proc_fops = &proc_scsi_operations;
return 0;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index fcd7455ffc39..a00eee6f7be9 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1828,7 +1828,7 @@ void scsi_scan_host(struct Scsi_Host *shost)
}
p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
- if (unlikely(IS_ERR(p)))
+ if (IS_ERR(p))
do_scan_async(data);
}
EXPORT_SYMBOL(scsi_scan_host);
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index ee8496aa0336..257e097c39af 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -107,6 +107,8 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
cmd->jiffies_at_alloc = jiffies;
cmd->request = rq;
+ cmd->cmnd = rq->cmd;
+
rq->special = cmd;
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 7899e3dda9bf..f4461d35ffb9 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -248,8 +248,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
else
q->queuedata = shost;
- set_bit(QUEUE_FLAG_BIDI, &q->queue_flags);
-
+ queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
return 0;
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3cea17dd5dba..01cefbb2d539 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -860,7 +860,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
static void sd_prepare_flush(struct request_queue *q, struct request *rq)
{
- memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = SD_TIMEOUT;
rq->cmd[0] = SYNCHRONIZE_CACHE;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 2029422bc04d..c9d7f721b9e2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -2667,7 +2667,6 @@ sg_proc_init(void)
{
int k, mask;
int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr);
- struct proc_dir_entry *pdep;
struct sg_proc_leaf * leaf;
sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL);
@@ -2676,13 +2675,10 @@ sg_proc_init(void)
for (k = 0; k < num_leaves; ++k) {
leaf = &sg_proc_leaf_arr[k];
mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO;
- pdep = create_proc_entry(leaf->name, mask, sg_proc_sgp);
- if (pdep) {
- leaf->fops->owner = THIS_MODULE,
- leaf->fops->read = seq_read,
- leaf->fops->llseek = seq_lseek,
- pdep->proc_fops = leaf->fops;
- }
+ leaf->fops->owner = THIS_MODULE;
+ leaf->fops->read = seq_read;
+ leaf->fops->llseek = seq_lseek;
+ proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops);
}
return 0;
}
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 640333b1e75c..329eb8780e74 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -744,7 +744,8 @@ static int wait_on_busy(unsigned long iobase, unsigned int loop) {
static int board_inquiry(unsigned int j) {
struct mscp *cpp;
dma_addr_t id_dma_addr;
- unsigned int time, limit = 0;
+ unsigned int limit = 0;
+ unsigned long time;
id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
@@ -1392,7 +1393,8 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
}
static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
- unsigned int i, j, time, k, c, limit = 0;
+ unsigned int i, j, k, c, limit = 0;
+ unsigned long time;
int arg_done = FALSE;
struct scsi_cmnd *SCpnt;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 2b8a410e0959..bbf5bc5892c7 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -200,7 +200,7 @@ static void rs_stop(struct tty_struct *tty)
local_irq_restore(flags);
}
-static void rs_put_char(char ch)
+static int rs_put_char(char ch)
{
int flags, loops = 0;
@@ -214,6 +214,7 @@ static void rs_put_char(char ch)
UTX_TXDATA = ch;
udelay(5);
local_irq_restore(flags);
+ return 1;
}
static void rs_start(struct tty_struct *tty)
@@ -1017,18 +1018,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(100) : 250);
return 0;
- case TIOCGSOFTCAR:
- error = put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- if (error)
- return error;
- return 0;
- case TIOCSSOFTCAR:
- get_user(arg, (unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
if (access_ok(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_struct)))
@@ -1061,9 +1050,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
-
change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1140,8 +1126,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index f59463601874..d9d4e9552a4d 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -995,10 +995,10 @@ static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
volatile QUICC_BD *bdp;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!tty)
- return;
+ return 0;
bdp = info->tx_cur;
while (bdp->status & BD_SC_READY);
@@ -1016,6 +1016,7 @@ static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
bdp++;
info->tx_cur = (QUICC_BD *)bdp;
+ return 1;
}
@@ -1246,7 +1247,7 @@ static int rs_360_tiocmget(struct tty_struct *tty, struct file *file)
#ifdef modem_control
unsigned char control, status;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
@@ -1277,12 +1278,12 @@ static int rs_360_tiocmset(struct tty_struct *tty, struct file *file,
ser_info_t *info = (ser_info_t *)tty->driver_data;
unsigned int arg;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
-
+ /* FIXME: locking on info->mcr */
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR)
@@ -1436,18 +1437,6 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
return retval;
end_break(info);
return 0;
- case TIOCGSOFTCAR:
- /* return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); */
- put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
- return 0;
- case TIOCSSOFTCAR:
- error = get_user(arg, (unsigned int *) arg);
- if (error)
- return error;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
#ifdef maybe
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
@@ -1665,8 +1654,7 @@ static void rs_360_close(struct tty_struct *tty, struct file * filp)
rs_360_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_360_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
info->event = 0;
@@ -1717,6 +1705,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
printk("jiff=%lu...", jiffies);
#endif
+ lock_kernel();
/* We go through the loop at least once because we can't tell
* exactly when the last character exits the shifter. There can
* be at least two characters waiting to be sent after the buffers
@@ -1745,6 +1734,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
bdp--;
} while (bdp->status & BD_SC_READY);
current->state = TASK_RUNNING;
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index ea41f2626458..a1ca9b7bf2d5 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2271,7 +2271,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
}
if (up->port.flags & UPF_IOREMAP) {
- up->port.membase = ioremap(up->port.mapbase, size);
+ up->port.membase = ioremap_nocache(up->port.mapbase,
+ size);
if (!up->port.membase) {
release_mem_region(up->port.mapbase, size);
ret = -ENOMEM;
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 38776e8b064b..f279745e9fef 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -153,10 +153,10 @@ static int __init parse_options(struct early_serial8250_device *device,
(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
port->membase += port->mapbase & ~PAGE_MASK;
#else
- port->membase = ioremap(port->mapbase, 64);
+ port->membase = ioremap_nocache(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
- __FUNCTION__,
+ __func__,
(unsigned long long)port->mapbase);
return -ENOMEM;
}
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 6e57382b9137..53fa19cf2f06 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -86,7 +86,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
len = pci_resource_len(dev, bar);
if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = ioremap(base, len);
+ priv->remapped_bar[bar] = ioremap_nocache(base, len);
if (!priv->remapped_bar[bar])
return -ENOMEM;
@@ -270,7 +270,7 @@ static int pci_plx9050_init(struct pci_dev *dev)
/*
* enable/disable interrupts
*/
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p == NULL)
return -ENOMEM;
writel(irq_config, p + 0x4c);
@@ -294,7 +294,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
/*
* disable interrupts
*/
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p != NULL) {
writel(0, p + 0x4c);
@@ -341,7 +341,8 @@ static int sbs_init(struct pci_dev *dev)
{
u8 __iomem *p;
- p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+ p = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
if (p == NULL)
return -ENOMEM;
@@ -365,7 +366,8 @@ static void __devexit sbs_exit(struct pci_dev *dev)
{
u8 __iomem *p;
- p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+ p = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
/* FIXME: What if resource_len < OCT_REG_CR_OFF */
if (p != NULL)
writeb(0, p + OCT_REG_CR_OFF);
@@ -419,7 +421,7 @@ static int pci_siig10x_init(struct pci_dev *dev)
break;
}
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p == NULL)
return -ENOMEM;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 34b809e3b596..62e6eb136a3c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -976,11 +976,15 @@ config SERIAL_68328_RTS_CTS
depends on SERIAL_68328
config SERIAL_COLDFIRE
- bool "ColdFire serial support"
+ bool "ColdFire serial support (DEPRECATED)"
depends on COLDFIRE
help
This driver supports the built-in serial ports of the Motorola ColdFire
family of CPUs.
+ This driver is deprecated because it supports only the old interface
+ for serial drivers and features like magic keys are not working.
+ Please switch to the new style driver because this driver will be
+ removed soon.
config SERIAL_MCF
bool "Coldfire serial support (new style driver)"
@@ -1355,4 +1359,47 @@ config SERIAL_SC26XX_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
+config SERIAL_BFIN_SPORT
+ tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
+ depends on BFIN && EXPERIMENTAL
+ select SERIAL_CORE
+ help
+ Enble support SPORT emulate UART on Blackfin series.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_sport_uart.
+
+choice
+ prompt "Baud rate for Blackfin SPORT UART"
+ depends on SERIAL_BFIN_SPORT
+ default SERIAL_SPORT_BAUD_RATE_57600
+ help
+ Choose a baud rate for the SPORT UART, other uart settings are
+ 8 bit, 1 stop bit, no parity, no flow control.
+
+config SERIAL_SPORT_BAUD_RATE_115200
+ bool "115200"
+
+config SERIAL_SPORT_BAUD_RATE_57600
+ bool "57600"
+
+config SERIAL_SPORT_BAUD_RATE_38400
+ bool "38400"
+
+config SERIAL_SPORT_BAUD_RATE_19200
+ bool "19200"
+
+config SERIAL_SPORT_BAUD_RATE_9600
+ bool "9600"
+endchoice
+
+config SPORT_BAUD_RATE
+ int
+ depends on SERIAL_BFIN_SPORT
+ default 115200 if (SERIAL_SPORT_BAUD_RATE_115200)
+ default 57600 if (SERIAL_SPORT_BAUD_RATE_57600)
+ default 38400 if (SERIAL_SPORT_BAUD_RATE_38400)
+ default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
+ default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index f02ff9fad017..0d9c09b1e836 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
+obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 5f55534a290b..d6b4ead693b7 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -65,9 +65,6 @@ static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
struct circ_buf *xmit = &uart->port.info->xmit;
-#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
- unsigned short ier;
-#endif
while (!(UART_GET_LSR(uart) & TEMT))
cpu_relax();
@@ -82,12 +79,8 @@ static void bfin_serial_stop_tx(struct uart_port *port)
#ifdef CONFIG_BF54x
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
- UART_CLEAR_IER(uart, ETBEI);
-#else
- ier = UART_GET_IER(uart);
- ier &= ~ETBEI;
- UART_PUT_IER(uart, ier);
#endif
+ UART_CLEAR_IER(uart, ETBEI);
#endif
}
@@ -102,14 +95,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
if (uart->tx_done)
bfin_serial_dma_tx_chars(uart);
#else
-#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
-#else
- unsigned short ier;
- ier = UART_GET_IER(uart);
- ier |= ETBEI;
- UART_PUT_IER(uart, ier);
-#endif
bfin_serial_tx_chars(uart);
#endif
}
@@ -120,21 +106,10 @@ static void bfin_serial_start_tx(struct uart_port *port)
static void bfin_serial_stop_rx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT) {
+#ifdef CONFIG_KGDB_UART
+ if (uart->port.line != CONFIG_KGDB_UART_PORT)
#endif
-#ifdef CONFIG_BF54x
UART_CLEAR_IER(uart, ERBFI);
-#else
- unsigned short ier;
-
- ier = UART_GET_IER(uart);
- ier &= ~ERBFI;
- UART_PUT_IER(uart, ier);
-#endif
-#ifdef CONFIG_KGDB_UART
- }
-#endif
}
/*
@@ -161,10 +136,7 @@ void kgdb_put_debug_char(int chr)
SSYNC();
}
-#ifndef CONFIG_BF54x
- UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
- SSYNC();
-#endif
+ UART_CLEAR_DLAB(uart);
UART_PUT_CHAR(uart, (unsigned char)chr);
SSYNC();
}
@@ -183,10 +155,7 @@ int kgdb_get_debug_char(void)
while(!(UART_GET_LSR(uart) & DR)) {
SSYNC();
}
-#ifndef CONFIG_BF54x
- UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
- SSYNC();
-#endif
+ UART_CLEAR_DLAB(uart);
chr = UART_GET_CHAR(uart);
SSYNC();
@@ -208,9 +177,6 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg;
static struct timeval anomaly_start = { .tv_sec = 0 };
-#ifdef CONFIG_KGDB_UART
- struct pt_regs *regs = get_irq_regs();
-#endif
status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
@@ -220,6 +186,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
#ifdef CONFIG_KGDB_UART
if (uart->port.line == CONFIG_KGDB_UART_PORT) {
+ struct pt_regs *regs = get_irq_regs();
if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
kgdb_breakkey_pressed(regs);
return;
@@ -391,7 +358,6 @@ static void bfin_serial_do_work(struct work_struct *work)
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
{
struct circ_buf *xmit = &uart->port.info->xmit;
- unsigned short ier;
uart->tx_done = 0;
@@ -429,13 +395,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
set_dma_x_modify(uart->tx_dma_channel, 1);
enable_dma(uart->tx_dma_channel);
-#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
-#else
- ier = UART_GET_IER(uart);
- ier |= ETBEI;
- UART_PUT_IER(uart, ier);
-#endif
}
static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
@@ -513,19 +473,12 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
struct circ_buf *xmit = &uart->port.info->xmit;
- unsigned short ier;
spin_lock(&uart->port.lock);
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
disable_dma(uart->tx_dma_channel);
clear_dma_irqstat(uart->tx_dma_channel);
-#ifdef CONFIG_BF54x
UART_CLEAR_IER(uart, ETBEI);
-#else
- ier = UART_GET_IER(uart);
- ier &= ~ETBEI;
- UART_PUT_IER(uart, ier);
-#endif
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
uart->port.icount.tx += uart->tx_count;
@@ -701,7 +654,6 @@ static int bfin_serial_startup(struct uart_port *port)
# endif
}
-
if (request_irq
(uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
"BFIN_UART_TX", uart)) {
@@ -710,11 +662,7 @@ static int bfin_serial_startup(struct uart_port *port)
return -EBUSY;
}
#endif
-#ifdef CONFIG_BF54x
UART_SET_IER(uart, ERBFI);
-#else
- UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
-#endif
return 0;
}
@@ -762,7 +710,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
break;
default:
printk(KERN_ERR "%s: word lengh not supported\n",
- __FUNCTION__);
+ __func__);
}
if (termios->c_cflag & CSTOPB)
@@ -810,26 +758,15 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
UART_PUT_IER(uart, 0);
#endif
-#ifndef CONFIG_BF54x
/* Set DLAB in LCR to Access DLL and DLH */
- val = UART_GET_LCR(uart);
- val |= DLAB;
- UART_PUT_LCR(uart, val);
- SSYNC();
-#endif
+ UART_SET_DLAB(uart);
UART_PUT_DLL(uart, quot & 0xFF);
- SSYNC();
UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
SSYNC();
-#ifndef CONFIG_BF54x
/* Clear DLAB in LCR to Access THR RBR IER */
- val = UART_GET_LCR(uart);
- val &= ~DLAB;
- UART_PUT_LCR(uart, val);
- SSYNC();
-#endif
+ UART_CLEAR_DLAB(uart);
UART_PUT_LCR(uart, lcr);
@@ -992,8 +929,7 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
status = UART_GET_IER(uart) & (ERBFI | ETBEI);
if (status == (ERBFI | ETBEI)) {
/* ok, the port was enabled */
- unsigned short lcr, val;
- unsigned short dlh, dll;
+ u16 lcr, dlh, dll;
lcr = UART_GET_LCR(uart);
@@ -1010,26 +946,18 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
case 2: *bits = 7; break;
case 3: *bits = 8; break;
}
-#ifndef CONFIG_BF54x
/* Set DLAB in LCR to Access DLL and DLH */
- val = UART_GET_LCR(uart);
- val |= DLAB;
- UART_PUT_LCR(uart, val);
-#endif
+ UART_SET_DLAB(uart);
dll = UART_GET_DLL(uart);
dlh = UART_GET_DLH(uart);
-#ifndef CONFIG_BF54x
/* Clear DLAB in LCR to Access THR RBR IER */
- val = UART_GET_LCR(uart);
- val &= ~DLAB;
- UART_PUT_LCR(uart, val);
-#endif
+ UART_CLEAR_DLAB(uart);
*baud = get_sclk() / (16*(dll | dlh << 8));
}
- pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
+ pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
#endif
@@ -1290,11 +1218,7 @@ static int __init bfin_serial_init(void)
request_irq(uart->port.irq, bfin_serial_rx_int,
IRQF_DISABLED, "BFIN_UART_RX", uart);
pr_info("Request irq for kgdb uart port\n");
-#ifdef CONFIG_BF54x
UART_SET_IER(uart, ERBFI);
-#else
- UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
-#endif
SSYNC();
t.c_cflag = CS8|B57600;
t.c_iflag = 0;
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
new file mode 100644
index 000000000000..aca1240ad808
--- /dev/null
+++ b/drivers/serial/bfin_sport_uart.c
@@ -0,0 +1,614 @@
+/*
+ * File: linux/drivers/serial/bfin_sport_uart.c
+ *
+ * Based on: drivers/serial/bfin_5xx.c by Aubrey Li.
+ * Author: Roy Huang <roy.huang@analog.com>
+ *
+ * Created: Nov 22, 2006
+ * Copyright: (c) 2006-2007 Analog Devices Inc.
+ * Description: this driver enable SPORTs on Blackfin emulate UART.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ */
+
+/* After reset, there is a prelude of low level pulse when transmit data first
+ * time. No addtional pulse in following transmit.
+ * According to document:
+ * The SPORTs are ready to start transmitting or receiving data no later than
+ * three serial clock cycles after they are enabled in the SPORTx_TCR1 or
+ * SPORTx_RCR1 register. No serial clock cycles are lost from this point on.
+ * The first internal frame sync will occur one frame sync delay after the
+ * SPORTs are ready. External frame syncs can occur as soon as the SPORT is
+ * ready.
+ */
+
+/* Thanks to Axel Alatalo <axel@rubico.se> for fixing sport rx bug. Sometimes
+ * sport receives data incorrectly. The following is Axel's words.
+ * As EE-191, sport rx samples 3 times of the UART baudrate and takes the
+ * middle smaple of every 3 samples as the data bit. For a 8-N-1 UART setting,
+ * 30 samples will be required for a byte. If transmitter sends a 1/3 bit short
+ * byte due to buadrate drift, then the 30th sample of a byte, this sample is
+ * also the third sample of the stop bit, will happens on the immediately
+ * following start bit which will be thrown away and missed. Thus since parts
+ * of the startbit will be missed and the receiver will begin to drift, the
+ * effect accumulates over time until synchronization is lost.
+ * If only require 2 samples of the stopbit (by sampling in total 29 samples),
+ * then a to short byte as in the case above will be tolerated. Then the 1/3
+ * early startbit will trigger a framesync since the last read is complete
+ * after only 2/3 stopbit and framesync is active during the last 1/3 looking
+ * for a possible early startbit. */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/delay.h>
+#include <asm/portmux.h>
+
+#include "bfin_sport_uart.h"
+
+unsigned short bfin_uart_pin_req_sport0[] =
+ {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+ P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0};
+
+unsigned short bfin_uart_pin_req_sport1[] =
+ {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+ P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0};
+
+#define DRV_NAME "bfin-sport-uart"
+
+struct sport_uart_port {
+ struct uart_port port;
+ char *name;
+
+ int tx_irq;
+ int rx_irq;
+ int err_irq;
+};
+
+static void sport_uart_tx_chars(struct sport_uart_port *up);
+static void sport_stop_tx(struct uart_port *port);
+
+static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
+{
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+ /* Place a Start and Stop bit */
+ __asm__ volatile (
+ "R2 = b#01111111100;\n\t"
+ "R3 = b#10000000001;\n\t"
+ "%0 <<= 2;\n\t"
+ "%0 = %0 & R2;\n\t"
+ "%0 = %0 | R3;\n\t"
+ :"=r"(value)
+ :"0"(value)
+ :"R2", "R3");
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+
+ SPORT_PUT_TX(up, value);
+}
+
+static inline unsigned int rx_one_byte(struct sport_uart_port *up)
+{
+ unsigned int value, extract;
+
+ value = SPORT_GET_RX32(up);
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+
+ /* Extract 8 bits data */
+ __asm__ volatile (
+ "R5 = 0;\n\t"
+ "P0 = 8;\n\t"
+ "R1 = 0x1801(Z);\n\t"
+ "R3 = 0x0300(Z);\n\t"
+ "R4 = 0;\n\t"
+ "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t"
+ "R2 = extract(%1, R1.L)(Z);\n\t"
+ "R2 <<= R4;\n\t"
+ "R5 = R5 | R2;\n\t"
+ "R1 = R1 - R3;\nloop_e:\t"
+ "R4 += 1;\n\t"
+ "%0 = R5;\n\t"
+ :"=r"(extract)
+ :"r"(value)
+ :"P0", "R1", "R2","R3","R4", "R5");
+
+ pr_debug(" extract:%x\n", extract);
+ return extract;
+}
+
+static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
+{
+ int tclkdiv, tfsdiv, rclkdiv;
+
+ /* Set TCR1 and TCR2 */
+ SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
+ SPORT_PUT_TCR2(up, 10);
+ pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+
+ /* Set RCR1 and RCR2 */
+ SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
+ SPORT_PUT_RCR2(up, 28);
+ pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+
+ tclkdiv = sclk/(2 * baud_rate) - 1;
+ tfsdiv = 12;
+ rclkdiv = sclk/(2 * baud_rate * 3) - 1;
+ SPORT_PUT_TCLKDIV(up, tclkdiv);
+ SPORT_PUT_TFSDIV(up, tfsdiv);
+ SPORT_PUT_RCLKDIV(up, rclkdiv);
+ SSYNC();
+ pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
+ __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
+
+ return 0;
+}
+
+static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
+{
+ struct sport_uart_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int ch;
+
+ do {
+ ch = rx_one_byte(up);
+ up->port.icount.rx++;
+
+ if (uart_handle_sysrq_char(&up->port, ch))
+ ;
+ else
+ tty_insert_flip_char(tty, ch, TTY_NORMAL);
+ } while (SPORT_GET_STAT(up) & RXNE);
+ tty_flip_buffer_push(tty);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
+{
+ sport_uart_tx_chars(dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
+{
+ struct sport_uart_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int stat = SPORT_GET_STAT(up);
+
+ /* Overflow in RX FIFO */
+ if (stat & ROVF) {
+ up->port.icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
+ }
+ /* These should not happen */
+ if (stat & (TOVF | TUVF | RUVF)) {
+ printk(KERN_ERR "SPORT Error:%s %s %s\n",
+ (stat & TOVF)?"TX overflow":"",
+ (stat & TUVF)?"TX underflow":"",
+ (stat & RUVF)?"RX underflow":"");
+ SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+ SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+ }
+ SSYNC();
+
+ return IRQ_HANDLED;
+}
+
+/* Reqeust IRQ, Setup clock */
+static int sport_startup(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ char buffer[20];
+ int retval;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ memset(buffer, 20, '\0');
+ snprintf(buffer, 20, "%s rx", up->name);
+ retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ return retval;
+ }
+
+ snprintf(buffer, 20, "%s tx", up->name);
+ retval = request_irq(up->tx_irq, sport_uart_tx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ goto fail1;
+ }
+
+ snprintf(buffer, 20, "%s err", up->name);
+ retval = request_irq(up->err_irq, sport_uart_err_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ goto fail2;
+ }
+
+ if (port->line) {
+ if (peripheral_request_list(bfin_uart_pin_req_sport1, DRV_NAME))
+ goto fail3;
+ } else {
+ if (peripheral_request_list(bfin_uart_pin_req_sport0, DRV_NAME))
+ goto fail3;
+ }
+
+ sport_uart_setup(up, get_sclk(), port->uartclk);
+
+ /* Enable receive interrupt */
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) | RSPEN));
+ SSYNC();
+
+ return 0;
+
+
+fail3:
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+
+ free_irq(up->err_irq, up);
+fail2:
+ free_irq(up->tx_irq, up);
+fail1:
+ free_irq(up->rx_irq, up);
+
+ return retval;
+
+}
+
+static void sport_uart_tx_chars(struct sport_uart_port *up)
+{
+ struct circ_buf *xmit = &up->port.info->xmit;
+
+ if (SPORT_GET_STAT(up) & TXF)
+ return;
+
+ if (up->port.x_char) {
+ tx_one_byte(up, up->port.x_char);
+ up->port.icount.tx++;
+ up->port.x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ sport_stop_tx(&up->port);
+ return;
+ }
+
+ while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
+ tx_one_byte(up, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+ up->port.icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
+}
+
+static unsigned int sport_tx_empty(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned int stat;
+
+ stat = SPORT_GET_STAT(up);
+ pr_debug("%s stat:%04x\n", __FUNCTION__, stat);
+ if (stat & TXHRE) {
+ return TIOCSER_TEMT;
+ } else
+ return 0;
+}
+
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_stop_tx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned int stat;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+
+ stat = SPORT_GET_STAT(up);
+ while(!(stat & TXHRE)) {
+ udelay(1);
+ stat = SPORT_GET_STAT(up);
+ }
+ /* Although the hold register is empty, last byte is still in shift
+ * register and not sent out yet. If baud rate is lower than default,
+ * delay should be longer. For example, if the baud rate is 9600,
+ * the delay must be at least 2ms by experience */
+ udelay(500);
+
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SSYNC();
+
+ return;
+}
+
+static void sport_start_tx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ /* Write data into SPORT FIFO before enable SPROT to transmit */
+ sport_uart_tx_chars(up);
+
+ /* Enable transmit, then an interrupt will generated */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+ SSYNC();
+ pr_debug("%s exit\n", __FUNCTION__);
+}
+
+static void sport_stop_rx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ /* Disable sport to stop rx */
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+ SSYNC();
+}
+
+static void sport_enable_ms(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_break_ctl(struct uart_port *port, int break_state)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_shutdown(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+
+ /* Disable sport */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+ SSYNC();
+
+ if (port->line) {
+ peripheral_free_list(bfin_uart_pin_req_sport1);
+ } else {
+ peripheral_free_list(bfin_uart_pin_req_sport0);
+ }
+
+ free_irq(up->rx_irq, up);
+ free_irq(up->tx_irq, up);
+ free_irq(up->err_irq, up);
+}
+
+static void sport_set_termios(struct uart_port *port,
+ struct termios *termios, struct termios *old)
+{
+ pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag);
+ uart_update_timeout(port, CS8 ,port->uartclk);
+}
+
+static const char *sport_type(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ return up->name;
+}
+
+static void sport_release_port(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static int sport_request_port(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return 0;
+}
+
+static void sport_config_port(struct uart_port *port, int flags)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ up->port.type = PORT_BFIN_SPORT;
+}
+
+static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return 0;
+}
+
+struct uart_ops sport_uart_ops = {
+ .tx_empty = sport_tx_empty,
+ .set_mctrl = sport_set_mctrl,
+ .get_mctrl = sport_get_mctrl,
+ .stop_tx = sport_stop_tx,
+ .start_tx = sport_start_tx,
+ .stop_rx = sport_stop_rx,
+ .enable_ms = sport_enable_ms,
+ .break_ctl = sport_break_ctl,
+ .startup = sport_startup,
+ .shutdown = sport_shutdown,
+ .set_termios = sport_set_termios,
+ .type = sport_type,
+ .release_port = sport_release_port,
+ .request_port = sport_request_port,
+ .config_port = sport_config_port,
+ .verify_port = sport_verify_port,
+};
+
+static struct sport_uart_port sport_uart_ports[] = {
+ { /* SPORT 0 */
+ .name = "SPORT0",
+ .tx_irq = IRQ_SPORT0_TX,
+ .rx_irq = IRQ_SPORT0_RX,
+ .err_irq= IRQ_SPORT0_ERROR,
+ .port = {
+ .type = PORT_BFIN_SPORT,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)SPORT0_TCR1,
+ .mapbase = SPORT0_TCR1,
+ .irq = IRQ_SPORT0_RX,
+ .uartclk = CONFIG_SPORT_BAUD_RATE,
+ .fifosize = 8,
+ .ops = &sport_uart_ops,
+ .line = 0,
+ },
+ }, { /* SPORT 1 */
+ .name = "SPORT1",
+ .tx_irq = IRQ_SPORT1_TX,
+ .rx_irq = IRQ_SPORT1_RX,
+ .err_irq= IRQ_SPORT1_ERROR,
+ .port = {
+ .type = PORT_BFIN_SPORT,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)SPORT1_TCR1,
+ .mapbase = SPORT1_TCR1,
+ .irq = IRQ_SPORT1_RX,
+ .uartclk = CONFIG_SPORT_BAUD_RATE,
+ .fifosize = 8,
+ .ops = &sport_uart_ops,
+ .line = 1,
+ },
+ }
+};
+
+static struct uart_driver sport_uart_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "SPORT-UART",
+ .dev_name = "ttySS",
+ .major = 204,
+ .minor = 84,
+ .nr = ARRAY_SIZE(sport_uart_ports),
+ .cons = NULL,
+};
+
+static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ if (sport)
+ uart_suspend_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static int sport_uart_resume(struct platform_device *dev)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ if (sport)
+ uart_resume_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static int sport_uart_probe(struct platform_device *dev)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ sport_uart_ports[dev->id].port.dev = &dev->dev;
+ uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
+ platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
+
+ return 0;
+}
+
+static int sport_uart_remove(struct platform_device *dev)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ platform_set_drvdata(dev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static struct platform_driver sport_uart_driver = {
+ .probe = sport_uart_probe,
+ .remove = sport_uart_remove,
+ .suspend = sport_uart_suspend,
+ .resume = sport_uart_resume,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init sport_uart_init(void)
+{
+ int ret;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ ret = uart_register_driver(&sport_uart_reg);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register %s:%d\n",
+ sport_uart_reg.driver_name, ret);
+ return ret;
+ }
+
+ ret = platform_driver_register(&sport_uart_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register sport uart driver:%d\n", ret);
+ uart_unregister_driver(&sport_uart_reg);
+ }
+
+
+ pr_debug("%s exit\n", __FUNCTION__);
+ return ret;
+}
+
+static void __exit sport_uart_exit(void)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ platform_driver_unregister(&sport_uart_driver);
+ uart_unregister_driver(&sport_uart_reg);
+}
+
+module_init(sport_uart_init);
+module_exit(sport_uart_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
new file mode 100644
index 000000000000..671d41cc1a3f
--- /dev/null
+++ b/drivers/serial/bfin_sport_uart.h
@@ -0,0 +1,63 @@
+/*
+ * File: linux/drivers/serial/bfin_sport_uart.h
+ *
+ * Based on: include/asm-blackfin/mach-533/bfin_serial_5xx.h
+ * Author: Roy Huang <roy.huang>analog.com>
+ *
+ * Created: Nov 22, 2006
+ * Copyright: (C) Analog Device Inc.
+ * Description: this driver enable SPORTs on Blackfin emulate UART.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */
+#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */
+#define OFFSET_TCLKDIV 0x08 /* Transmit Serial Clock Divider Register */
+#define OFFSET_TFSDIV 0x0C /* Transmit Frame Sync Divider Register */
+#define OFFSET_TX 0x10 /* Transmit Data Register */
+#define OFFSET_RX 0x18 /* Receive Data Register */
+#define OFFSET_RCR1 0x20 /* Receive Configuration 1 Register */
+#define OFFSET_RCR2 0x24 /* Receive Configuration 2 Register */
+#define OFFSET_RCLKDIV 0x28 /* Receive Serial Clock Divider Register */
+#define OFFSET_RFSDIV 0x2c /* Receive Frame Sync Divider Register */
+#define OFFSET_STAT 0x30 /* Status Register */
+
+#define SPORT_GET_TCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR1))
+#define SPORT_GET_TCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR2))
+#define SPORT_GET_TCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
+#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
+#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX))
+#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX))
+#define SPORT_GET_RX32(sport) bfin_read32(((sport)->port.membase + OFFSET_RX))
+#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))
+#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2))
+#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
+#define SPORT_GET_RFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
+#define SPORT_GET_STAT(sport) bfin_read16(((sport)->port.membase + OFFSET_STAT))
+
+#define SPORT_PUT_TCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
+#define SPORT_PUT_TCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
+#define SPORT_PUT_TCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
+#define SPORT_PUT_TFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
+#define SPORT_PUT_TX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TX), v)
+#define SPORT_PUT_RX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RX), v)
+#define SPORT_PUT_RCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
+#define SPORT_PUT_RCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
+#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
+#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
+#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index a638ba0679ac..a19dc7ef8861 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -1117,7 +1117,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
line = cpm_uart_id2nr(idx);
if(line < 0) {
- printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
+ printk(KERN_ERR"%s(): port %d is not registered", __func__, idx);
return -EINVAL;
}
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 88e7c1d5b919..3e0366eab412 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -1788,7 +1788,7 @@ static unsigned int handle_descr_data(struct e100_serial *info,
if (info->recv_cnt + recvl > 65536) {
printk(KERN_CRIT
- "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl);
+ "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
return 0;
}
@@ -1801,7 +1801,7 @@ static unsigned int handle_descr_data(struct e100_serial *info,
append_recv_buffer(info, buffer);
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
- panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr->buf = virt_to_phys(buffer->buffer);
@@ -1925,7 +1925,7 @@ static int start_recv_dma(struct e100_serial *info)
/* Set up the receiving descriptors */
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
- panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr[i].ctrl = d_int;
descr[i].buf = virt_to_phys(buffer->buffer);
@@ -3581,8 +3581,9 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
- lock_kernel();
+ local_irq_save(flags);
if (clear & TIOCM_RTS)
e100_rts(info, 0);
@@ -3604,7 +3605,7 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
if (set & TIOCM_CD)
e100_cd_out(info, 1);
- unlock_kernel();
+ local_irq_restore(flags);
return 0;
}
@@ -3613,8 +3614,10 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned int result;
+ unsigned long flags;
+
+ local_irq_save(flags);
- lock_kernel();
result =
(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
@@ -3623,7 +3626,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
- unlock_kernel();
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_IO
printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
@@ -3702,10 +3705,6 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
-
change_speed(info);
/* Handle turning off CRTSCTS */
@@ -3808,10 +3807,8 @@ rs_close(struct tty_struct *tty, struct file * filp)
#endif
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
+ rs_flush_buffer(tty);
+ tty_ldisc_flush(tty);
tty->closing = 0;
info->event = 0;
info->tty = 0;
@@ -3885,6 +3882,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
* Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
* R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
*/
+ lock_kernel();
orig_jiffies = jiffies;
while (info->xmit.head != info->xmit.tail || /* More in send queue */
(*info->ostatusadr & 0x007f) || /* more in FIFO */
@@ -3901,6 +3899,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
curr_time_usec - info->last_tx_active_usec;
}
set_current_state(TASK_RUNNING);
+ unlock_kernel();
}
/*
@@ -4520,7 +4519,7 @@ rs_init(void)
if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
- panic("%s: Failed to request irq8", __FUNCTION__);
+ panic("%s: Failed to request irq8", __func__);
#endif
#endif /* CONFIG_SVINTO_SIM */
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 168073f12cec..4f1af71e9a1b 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -52,7 +52,7 @@ static unsigned int Submodule_slot;
#define DPRINT_CONFIG(_x...) ;
//#define DPRINT_CONFIG(_x...) printk _x
#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS() printk("%s : fails %d\n", __FUNCTION__, __LINE__)
+//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__)
/* number of characters we want to transmit to the lower level at a time */
#define MAX_CHARS 256
@@ -445,7 +445,7 @@ static int inline port_init(struct ioc3_port *port)
sbbr_h = &idd->vma->sbbr_h;
ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
- __FUNCTION__, (void *)ring_pci_addr));
+ __func__, (void *)ring_pci_addr));
writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
@@ -593,7 +593,7 @@ config_port(struct ioc3_port *port,
DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
"parodd %d\n",
- __FUNCTION__, ((struct uart_port *)port->ip_port)->line,
+ __func__, ((struct uart_port *)port->ip_port)->line,
baud, byte_size, stop_bits, parenb, parodd));
if (set_baud(port, baud))
@@ -871,14 +871,14 @@ static int ioc3_set_proto(struct ioc3_port *port, int proto)
default:
case PROTO_RS232:
/* Clear the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs232\n", __FUNCTION__));
+ DPRINT_CONFIG(("%s: rs232\n", __func__));
writel(0, (&port->ip_idd->vma->gppr[0]
+ hooks->rs422_select_pin));
break;
case PROTO_RS422:
/* Set the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs422\n", __FUNCTION__));
+ DPRINT_CONFIG(("%s: rs422\n", __func__));
writel(1, (&port->ip_idd->vma->gppr[0]
+ hooks->rs422_select_pin));
break;
@@ -988,7 +988,7 @@ ioc3_change_speed(struct uart_port *the_port,
}
baud = uart_get_baud_rate(the_port, new_termios, old_termios,
MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __FUNCTION__, baud,
+ DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
the_port->line));
if (!the_port->fifosize)
@@ -1026,7 +1026,7 @@ ioc3_change_speed(struct uart_port *the_port,
DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
"config_port(baud %d data %d stop %d penable %d "
" parity %d), notification 0x%x\n",
- __FUNCTION__, (void *)port, the_port->line, cflag, baud,
+ __func__, (void *)port, the_port->line, cflag, baud,
new_data, new_stop, new_parity_enable, new_parity,
the_port->ignore_status_mask));
@@ -1919,7 +1919,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
struct pci_dev *pdev = idd->pdev;
DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
- __FUNCTION__, pdev, (void *)card_ptr));
+ __func__, pdev, (void *)card_ptr));
if (!card_ptr)
return -ENODEV;
@@ -1933,7 +1933,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
port->ip_port = the_port;
DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
- __FUNCTION__, (void *)the_port, (void *)port,
+ __func__, (void *)the_port, (void *)port,
phys_port, ii));
/* membase, iobase and mapbase just need to be non-0 */
@@ -1950,7 +1950,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
printk(KERN_WARNING
"%s: unable to add port %d bus %d\n",
- __FUNCTION__, the_port->line, pdev->bus->number);
+ __func__, the_port->line, pdev->bus->number);
} else {
DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
the_port->line, the_port->irq, pdev->bus->number));
@@ -2017,7 +2017,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
struct ioc3_port *ports[PORTS_PER_CARD];
int phys_port;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd));
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
if (!card_ptr) {
@@ -2067,7 +2067,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
"ip_uart_regs 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_serial_regs,
(void *)port->ip_uart_regs));
@@ -2082,7 +2082,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p, ip_inring 0x%p "
"ip_outring 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf,
(void *)port->ip_inring,
@@ -2094,7 +2094,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
"ip_uart_regs 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_serial_regs,
(void *)port->ip_uart_regs));
@@ -2108,7 +2108,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p, ip_inring 0x%p "
"ip_outring 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf,
(void *)port->ip_inring,
@@ -2116,7 +2116,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
}
DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
- __FUNCTION__,
+ __func__,
phys_port, (void *)port, (void *)card_ptr));
DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
(void *)port->ip_serial_regs,
@@ -2127,7 +2127,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
"outring 0x%p\n",
- __FUNCTION__,
+ __func__,
phys_port, (void *)port,
(void *)port->ip_inring,
(void *)port->ip_outring));
@@ -2170,7 +2170,7 @@ static int __devinit ioc3uart_init(void)
if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register IOC3 uart serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
ret = ioc3_register_submodule(&ioc3uart_submodule);
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 0c179384fb0c..49b8a82b7b9f 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -889,7 +889,7 @@ static int inline port_init(struct ioc4_port *port)
ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
- __FUNCTION__, ring_pci_addr));
+ __func__, ring_pci_addr));
writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
@@ -1028,7 +1028,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg)
spin_lock_irqsave(&soft->is_ir_lock, flag);
printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
"other_ir 0x%x other_ies 0x%x mask 0x%x\n",
- __FUNCTION__, __LINE__,
+ __func__, __LINE__,
(void *)mem, readl(&mem->sio_ir.raw),
readl(&mem->sio_ies.raw),
readl(&mem->other_ir.raw),
@@ -1155,14 +1155,14 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
(TOTAL_RING_BUF_SIZE - 1)) == 0));
DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf));
port->ip_inring = RING(port, RX_0_OR_2);
port->ip_outring = RING(port, TX_0_OR_2);
}
DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
- __FUNCTION__,
+ __func__,
port_number, (void *)port, (void *)control));
DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
(void *)port->ip_serial_regs,
@@ -1173,7 +1173,7 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
"outring 0x%p\n",
- __FUNCTION__,
+ __func__,
port_number, (void *)port,
(void *)port->ip_inring,
(void *)port->ip_outring));
@@ -1317,7 +1317,7 @@ config_port(struct ioc4_port *port,
int spiniter = 0;
DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
- __FUNCTION__, baud, byte_size, stop_bits, parenb, parodd));
+ __func__, baud, byte_size, stop_bits, parenb, parodd));
if (set_baud(port, baud))
return 1;
@@ -1725,7 +1725,7 @@ ioc4_change_speed(struct uart_port *the_port,
}
baud = uart_get_baud_rate(the_port, new_termios, old_termios,
MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d\n", __FUNCTION__, baud));
+ DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
/* default is 9600 */
if (!baud)
@@ -1765,7 +1765,7 @@ ioc4_change_speed(struct uart_port *the_port,
DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
"config_port(baud %d data %d stop %d p enable %d parity %d),"
" notification 0x%x\n",
- __FUNCTION__, (void *)port, cflag, baud, new_data, new_stop,
+ __func__, (void *)port, cflag, baud, new_data, new_stop,
new_parity_enable, new_parity, the_port->ignore_status_mask));
if ((config_port(port, baud, /* baud */
@@ -2715,7 +2715,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
- __FUNCTION__, pdev, (void *)control));
+ __func__, pdev, (void *)control));
if (!control)
return -ENODEV;
@@ -2734,7 +2734,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
port->ip_all_ports[port_type_idx] = the_port;
DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
- __FUNCTION__, (void *)the_port,
+ __func__, (void *)the_port,
(void *)port,
port_type == PROTO_RS232 ? "rs232" : "rs422"));
@@ -2752,7 +2752,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
if (uart_add_one_port(u_driver, the_port) < 0) {
printk(KERN_WARNING
"%s: unable to add port %d bus %d\n",
- __FUNCTION__, the_port->line, pdev->bus->number);
+ __func__, the_port->line, pdev->bus->number);
} else {
DPRINT_CONFIG(
("IOC4 serial port %d irq = %d, bus %d\n",
@@ -2777,7 +2777,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
int ret = 0;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev,
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
idd->idd_pci_id));
/* PCI-RT does not bring out serial connections.
@@ -2806,7 +2806,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
goto out2;
}
DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
- __FUNCTION__, (void *)idd->idd_misc_regs,
+ __func__, (void *)idd->idd_misc_regs,
(void *)serial));
/* Get memory for the new card */
@@ -2858,7 +2858,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
} else {
printk(KERN_WARNING
"%s : request_irq fails for IRQ 0x%x\n ",
- __FUNCTION__, idd->idd_pdev->irq);
+ __func__, idd->idd_pdev->irq);
}
ret = ioc4_attach_local(idd);
if (ret)
@@ -2911,13 +2911,13 @@ int ioc4_serial_init(void)
if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register rs232 IOC4 serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register rs422 IOC4 serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 12c934a1f274..8871aaa3dba6 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -373,6 +373,7 @@ struct neo_uart_struct {
#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI"
#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM"
/*
* Our Global Variables.
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 6767ee381cd1..338cf8a08b43 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -82,7 +82,10 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
brd->pci_dev = pdev;
- brd->maxports = 2;
+ if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+ brd->maxports = 4;
+ else
+ brd->maxports = 2;
spin_lock_init(&brd->bd_lock);
spin_lock_init(&brd->bd_intr_lock);
@@ -208,6 +211,7 @@ static struct pci_device_id jsm_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index 9cf03327386a..eadc1ab6bbce 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -96,12 +96,14 @@ static void cleanup_kgdboc(void)
static int kgdboc_get_char(void)
{
- return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line);
+ return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
+ kgdb_tty_line);
}
static void kgdboc_put_char(u8 chr)
{
- kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr);
+ kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
+ kgdb_tty_line, chr);
}
static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index ddd3aa50d4ad..56007cc8a9b3 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -1,3 +1,4 @@
+#warning This driver is deprecated. Check Kconfig for details.
/*
* mcfserial.c -- serial driver for ColdFire internal UARTS.
*
@@ -1072,18 +1073,6 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0;
- case TIOCGSOFTCAR:
- error = put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- if (error)
- return error;
- return 0;
- case TIOCSSOFTCAR:
- get_user(arg, (unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
if (access_ok(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_struct)))
@@ -1222,8 +1211,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp)
} else
#endif
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mcfrs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1276,6 +1264,8 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
+ lock_kernel();
+
fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
char_time = fifo_time / 5;
if (char_time == 0)
@@ -1312,6 +1302,7 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
+ unlock_kernel();
#else
/*
* For the other coldfire models, assume all data has been sent
@@ -1907,7 +1898,7 @@ static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
* This is used for console output.
*/
-void mcfrs_put_char(char ch)
+int mcfrs_put_char(char ch)
{
volatile unsigned char *uartp;
unsigned long flags;
@@ -1931,7 +1922,7 @@ void mcfrs_put_char(char ch)
mcfrs_init_console(); /* try and get it back */
local_irq_restore(flags);
- return;
+ return 1;
}
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index d93b3578c5e2..efc971d9647b 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -783,7 +783,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
}
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tty);
+ spin_lock(&port->lock);
return psc_ops->raw_rx_rdy(port);
}
@@ -1221,8 +1223,8 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
#endif
#ifdef CONFIG_PPC_MPC512x
{ .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
- {},
#endif
+ {},
};
static int __devinit
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index 3123ffeac8ad..81ac9bb4f39b 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -287,6 +287,7 @@ static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned int val;
+ /* FIXME: Locking needed ? */
if (mctrl & TIOCM_RTS) {
val = readl(port->membase + UART_RTS_CR);
writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 4ffa2585429a..2b6a013639e6 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1022,6 +1022,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
struct uart_port *port = &ourport->port;
struct s3c2410_uartcfg *cfg;
struct resource *res;
+ int ret;
dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
@@ -1064,9 +1065,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->mapbase = res->start;
port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
- port->irq = platform_get_irq(platdev, 0);
- if (port->irq < 0)
+ ret = platform_get_irq(platdev, 0);
+ if (ret < 0)
port->irq = 0;
+ else
+ port->irq = ret;
ourport->clk = clk_get(&platdev->dev, "uart");
@@ -1093,13 +1096,13 @@ static int s3c24xx_serial_probe(struct platform_device *dev,
ourport = &s3c24xx_serial_ports[probe_index];
probe_index++;
- dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);
+ dbg("%s: initialising port %p...\n", __func__, ourport);
ret = s3c24xx_serial_init_port(ourport, info, dev);
if (ret < 0)
goto probe_err;
- dbg("%s: adding port\n", __FUNCTION__);
+ dbg("%s: adding port\n", __func__);
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
platform_set_drvdata(dev, &ourport->port);
@@ -1584,7 +1587,7 @@ static int s3c2412_serial_resetport(struct uart_port *port,
unsigned long ucon = rd_regl(port, S3C2410_UCON);
dbg("%s: port=%p (%08lx), cfg=%p\n",
- __FUNCTION__, port, port->mapbase, cfg);
+ __func__, port, port->mapbase, cfg);
/* ensure we don't change the clock settings... */
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index 67b2338913c2..62b38582f5e9 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -655,7 +655,7 @@ void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns)
void __init sa1100_register_uart(int idx, int port)
{
if (idx >= NR_PORTS) {
- printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx);
+ printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
return;
}
@@ -682,7 +682,7 @@ void __init sa1100_register_uart(int idx, int port)
break;
default:
- printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port);
+ printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
}
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 977ce820ce30..eab032733790 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -422,6 +422,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
EXPORT_SYMBOL(uart_get_divisor);
+/* FIXME: Consistent locking policy */
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
@@ -454,27 +455,30 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
port->ops->set_termios(port, termios, old_termios);
}
-static inline void
+static inline int
__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
{
unsigned long flags;
+ int ret = 0;
if (!circ->buf)
- return;
+ return 0;
spin_lock_irqsave(&port->lock, flags);
if (uart_circ_chars_free(circ) != 0) {
circ->buf[circ->head] = c;
circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+ ret = 1;
}
spin_unlock_irqrestore(&port->lock, flags);
+ return ret;
}
-static void uart_put_char(struct tty_struct *tty, unsigned char ch)
+static int uart_put_char(struct tty_struct *tty, unsigned char ch)
{
struct uart_state *state = tty->driver_data;
- __uart_put_char(state->port, &state->info->xmit, ch);
+ return __uart_put_char(state->port, &state->info->xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
@@ -528,21 +532,31 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
static int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_free(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_free(&state->info->xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_pending(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_pending(&state->info->xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static void uart_flush_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
- struct uart_port *port = state->port;
+ struct uart_port *port;
unsigned long flags;
/*
@@ -554,6 +568,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
return;
}
+ port = state->port;
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
@@ -618,6 +633,11 @@ static int uart_get_info(struct uart_state *state,
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
+
+ /* Ensure the state we copy is consistent and no hardware changes
+ occur as we go */
+ mutex_lock(&state->mutex);
+
tmp.type = port->type;
tmp.line = port->line;
tmp.port = port->iobase;
@@ -637,6 +657,8 @@ static int uart_get_info(struct uart_state *state,
tmp.iomem_reg_shift = port->regshift;
tmp.iomem_base = (void *)(unsigned long)port->mapbase;
+ mutex_unlock(&state->mutex);
+
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -914,8 +936,6 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
- BUG_ON(!kernel_locked());
-
mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN)
@@ -1059,7 +1079,7 @@ static int uart_get_count(struct uart_state *state,
}
/*
- * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
+ * Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
@@ -1069,7 +1089,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
- BUG_ON(!kernel_locked());
/*
* These ioctls don't rely on the hardware to be present.
@@ -1140,9 +1159,9 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
break;
}
}
- out_up:
+out_up:
mutex_unlock(&state->mutex);
- out:
+out:
return ret;
}
@@ -1153,7 +1172,6 @@ static void uart_set_termios(struct tty_struct *tty,
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
- BUG_ON(!kernel_locked());
/*
* These are the bits that are used to setup various
@@ -1165,8 +1183,9 @@ static void uart_set_termios(struct tty_struct *tty,
if ((cflag ^ old_termios->c_cflag) == 0 &&
tty->termios->c_ospeed == old_termios->c_ospeed &&
tty->termios->c_ispeed == old_termios->c_ispeed &&
- RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
return;
+ }
uart_change_speed(state, old_termios);
@@ -1200,7 +1219,6 @@ static void uart_set_termios(struct tty_struct *tty,
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
-
#if 0
/*
* No need to wake up processes in open wait, since they
@@ -1316,11 +1334,11 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
struct uart_port *port = state->port;
unsigned long char_time, expire;
- BUG_ON(!kernel_locked());
-
if (port->type == PORT_UNKNOWN || port->fifosize == 0)
return;
+ lock_kernel();
+
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -1366,6 +1384,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
set_current_state(TASK_RUNNING); /* might not be needed */
+ unlock_kernel();
}
/*
@@ -2079,7 +2098,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
int ret;
uart_change_pm(state, 0);
+ spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
+ spin_unlock_irq(&port->lock);
ret = ops->startup(port);
if (ret == 0) {
uart_change_speed(state, NULL);
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index c2ea5d4df44a..8fdafc27fce8 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -42,14 +42,12 @@
#include <linux/console.h>
#include <linux/platform_device.h>
#include <linux/serial_sci.h>
-
-#ifdef CONFIG_CPU_FREQ
#include <linux/notifier.h>
#include <linux/cpufreq.h>
-#endif
-
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#include <linux/clk.h>
#include <linux/ctype.h>
+
+#ifdef CONFIG_SUPERH
#include <asm/clock.h>
#include <asm/sh_bios.h>
#include <asm/kgdb.h>
@@ -80,7 +78,7 @@ struct sci_port {
struct timer_list break_timer;
int break_flag;
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#ifdef CONFIG_SUPERH
/* Port clock */
struct clk *clk;
#endif
@@ -365,21 +363,19 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
unsigned int fcr_val = 0;
+ unsigned short data;
- if (cflag & CRTSCTS) {
- fcr_val |= SCFCR_MCE;
-
- ctrl_outw(0x0000, PORT_PSCR);
- } else {
- unsigned short data;
-
- data = ctrl_inw(PORT_PSCR);
- data &= 0x033f;
- data |= 0x0400;
- ctrl_outw(data, PORT_PSCR);
+ if (port->mapbase == 0xffe00000) {
+ data = ctrl_inw(PSCR);
+ data &= ~0x03cf;
+ if (cflag & CRTSCTS)
+ fcr_val |= SCFCR_MCE;
+ else
+ data |= 0x0340;
- ctrl_outw(ctrl_inw(SCSPTR0) & 0x17, SCSPTR0);
+ ctrl_outw(data, PSCR);
}
+ /* SCIF1 and SCIF2 should be setup by board code */
sci_out(port, SCFCR, fcr_val);
}
@@ -855,7 +851,7 @@ static int sci_notifier(struct notifier_block *self,
printk(KERN_INFO "%s: got a postchange notification "
"for cpu %d (old %d, new %d)\n",
- __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+ __func__, freqs->cpu, freqs->old, freqs->new);
}
return NOTIFY_OK;
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index fa8700a968fc..eb84833233fd 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -76,12 +76,13 @@
# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */
-# define SCSPTR0 SCPDR0
+# define PADR 0xA4050120
+# define PSDR 0xA405013e
+# define PWDR 0xA4050166
+# define PSCR 0xA405011E
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
-# define PORT_PSCR 0xA405011E
#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */
# define SCSPTR0 SCPDR0
@@ -320,7 +321,7 @@
unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
ctrl_outb(value, addr); \
- } else { \
+ } else if ((size) == 16) { \
ctrl_outw(value, addr); \
}
@@ -451,7 +452,11 @@ SCIF_FNS(SCSPTR, 0, 0, 0x24, 16)
SCIF_FNS(SCLSR, 0, 0, 0x28, 16)
#else
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+SCIF_FNS(SCSPTR, 0, 0, 0, 0)
+#else
SCIF_FNS(SCSPTR, 0, 0, 0x20, 16)
+#endif
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
#endif
#endif
@@ -593,13 +598,25 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722) || defined(CONFIG_CPU_SUBTYPE_SH7366)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
return ctrl_inb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
return 1;
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xffe00000)
+ return ctrl_inb(PSDR) & 0x02 ? 1 : 0; /* SCIF0 */
+ if (port->mapbase == 0xffe10000)
+ return ctrl_inb(PADR) & 0x40 ? 1 : 0; /* SCIF1 */
+ if (port->mapbase == 0xffe20000)
+ return ctrl_inb(PWDR) & 0x04 ? 1 : 0; /* SCIF2 */
+
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
static inline int sci_rxd_in(struct uart_port *port)
{
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 41fc61264443..019da2e05f0b 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -839,7 +839,7 @@ static int __init sn_sal_module_init(void)
if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
/* error - not sure what I'd do - so I'll do nothing */
- printk(KERN_ERR "%s: unable to add port\n", __FUNCTION__);
+ printk(KERN_ERR "%s: unable to add port\n", __func__);
}
/* when this driver is compiled in, the console initialization
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index be0fe152891b..145c0281495d 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -392,7 +392,7 @@ static struct uart_ops sunhv_pops = {
static struct uart_driver sunhv_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sunhv",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 543f93741e6f..9ff5b38f3bee 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -826,7 +826,7 @@ static struct uart_ops sunsab_pops = {
static struct uart_driver sunsab_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sunsab",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 4e2302d43ab1..03806a935209 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1173,7 +1173,7 @@ out:
static struct uart_driver sunsu_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sunsu",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 90a20a152ebf..7e9fa5ef0eb7 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1023,7 +1023,7 @@ static struct uart_sunzilog_port *sunzilog_irq_chain;
static struct uart_driver sunzilog_reg = {
.owner = THIS_MODULE,
- .driver_name = "ttyS",
+ .driver_name = "sunzilog",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index b565d5a37499..b51c24245be4 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -584,7 +584,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match)
const unsigned int *id;
int irq, rc;
- dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match);
+ dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
rc = of_address_to_resource(op->node, 0, &res);
if (rc) {
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 5e4310ccd591..01917c433f17 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -215,7 +215,7 @@ static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port)
return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%p\n", __FUNCTION__, addr);
+ printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
BUG();
return 0;
}
@@ -234,7 +234,7 @@ static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%x\n", __FUNCTION__, addr);
+ printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
BUG();
return NULL;
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index fae9e8f3d092..66ec5d8808de 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -126,7 +126,6 @@ config SPI_MPC52xx_PSC
config SPI_MPC83xx
tristate "Freescale MPC83xx/QUICC Engine SPI controller"
depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
- select SPI_BITBANG
help
This enables using the Freescale MPC83xx and QUICC Engine SPI
controllers in master mode.
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 02c8e305b14f..e81d59d78910 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -497,7 +497,7 @@ 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 long bus_hz;
unsigned int npcs_pin;
int ret;
@@ -536,14 +536,25 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
- /* speed zero convention is used by some upper layers */
+ /*
+ * Pre-new_1 chips start out at half the peripheral
+ * bus speed.
+ */
bus_hz = clk_get_rate(as->clk);
+ if (!as->new_1)
+ bus_hz /= 2;
+
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);
+ /*
+ * Calculate the lowest divider that satisfies the
+ * constraint, assuming div32/fdiv/mbz == 0.
+ */
+ scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz);
+
+ /*
+ * If the resulting divider doesn't fit into the
+ * register bitfield, we can't satisfy the constraint.
+ */
if (scbr >= (1 << SPI_SCBR_SIZE)) {
dev_dbg(&spi->dev,
"setup: %d Hz too slow, scbr %u; min %ld Hz\n",
@@ -551,8 +562,8 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
} else
+ /* speed zero means "as slow as possible" */
scbr = 0xff;
- sck_hz = bus_hz / scbr;
csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
if (spi->mode & SPI_CPOL)
@@ -589,7 +600,7 @@ static int atmel_spi_setup(struct spi_device *spi)
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);
+ bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 90729469d481..681d62325d3d 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -1,5 +1,5 @@
/*
- * MPC52xx SPC in SPI mode driver.
+ * MPC52xx PSC in SPI mode driver.
*
* Maintainer: Dragos Carp
*
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 654bb58be630..0c452c46ab07 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1567,7 +1567,7 @@ static int pxa2xx_spi_resume(struct platform_device *pdev)
int status = 0;
/* Enable the SSP clock */
- clk_disable(ssp->clk);
+ clk_enable(ssp->clk);
/* Start the queue running */
status = start_queue(drv_data);
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index a9ac1fdb3094..7fea3cf4588a 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -608,6 +608,7 @@ static void pump_transfers(unsigned long data)
u8 width;
u16 cr, dma_width, dma_config;
u32 tranf_success = 1;
+ u8 full_duplex = 0;
/* Get current state information */
message = drv_data->cur_msg;
@@ -658,6 +659,7 @@ static void pump_transfers(unsigned long data)
}
if (transfer->rx_buf != NULL) {
+ full_duplex = transfer->tx_buf != NULL;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len;
dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
@@ -740,7 +742,8 @@ static void pump_transfers(unsigned long data)
* successful use different way to r/w according to
* drv_data->cur_chip->enable_dma
*/
- if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+ if (!full_duplex && drv_data->cur_chip->enable_dma
+ && drv_data->len > 6) {
disable_dma(drv_data->dma_channel);
clear_dma_irqstat(drv_data->dma_channel);
@@ -828,7 +831,7 @@ static void pump_transfers(unsigned long data)
/* IO mode write then read */
dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
- if (drv_data->tx != NULL && drv_data->rx != NULL) {
+ if (full_duplex) {
/* full duplex mode */
BUG_ON((drv_data->tx_end - drv_data->tx) !=
(drv_data->rx_end - drv_data->rx));
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 189f706b9e4b..6832da6f7109 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -49,6 +49,7 @@ struct mpc83xx_spi_reg {
#define SPMODE_LEN(x) ((x) << 20)
#define SPMODE_PM(x) ((x) << 16)
#define SPMODE_OP (1 << 14)
+#define SPMODE_CG(x) ((x) << 7)
/*
* Default for SPI Mode:
@@ -67,10 +68,6 @@ struct mpc83xx_spi_reg {
/* SPI Controller driver's private data. */
struct mpc83xx_spi {
- /* bitbang has to be first */
- struct spi_bitbang bitbang;
- struct completion done;
-
struct mpc83xx_spi_reg __iomem *base;
/* rx & tx bufs from the spi_transfer */
@@ -82,7 +79,7 @@ struct mpc83xx_spi {
u32(*get_tx) (struct mpc83xx_spi *);
unsigned int count;
- u32 irq;
+ int irq;
unsigned nsecs; /* (clock cycle time)/2 */
@@ -94,6 +91,25 @@ struct mpc83xx_spi {
void (*activate_cs) (u8 cs, u8 polarity);
void (*deactivate_cs) (u8 cs, u8 polarity);
+
+ u8 busy;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+
+ struct list_head queue;
+ spinlock_t lock;
+
+ struct completion done;
+};
+
+struct spi_mpc83xx_cs {
+ /* functions to deal with different sized buffers */
+ void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
+ u32 (*get_tx) (struct mpc83xx_spi *);
+ u32 rx_shift; /* RX data reg shift when in qe mode */
+ u32 tx_shift; /* TX data reg shift when in qe mode */
+ u32 hw_mode; /* Holds HW mode register settings */
};
static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val)
@@ -137,6 +153,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
{
struct mpc83xx_spi *mpc83xx_spi;
u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+ struct spi_mpc83xx_cs *cs = spi->controller_state;
mpc83xx_spi = spi_master_get_devdata(spi->master);
@@ -147,50 +164,26 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
if (value == BITBANG_CS_ACTIVE) {
u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
- u32 len = spi->bits_per_word;
- u8 pm;
- if (len == 32)
- len = 0;
- else
- len = len - 1;
-
- /* mask out bits we are going to set */
- regval &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
- | SPMODE_LEN(0xF) | SPMODE_DIV16
- | SPMODE_PM(0xF) | SPMODE_REV | SPMODE_LOOP);
-
- if (spi->mode & SPI_CPHA)
- regval |= SPMODE_CP_BEGIN_EDGECLK;
- if (spi->mode & SPI_CPOL)
- regval |= SPMODE_CI_INACTIVEHIGH;
- if (!(spi->mode & SPI_LSB_FIRST))
- regval |= SPMODE_REV;
- if (spi->mode & SPI_LOOP)
- regval |= SPMODE_LOOP;
-
- regval |= SPMODE_LEN(len);
-
- if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) {
- pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64) - 1;
- if (pm > 0x0f) {
- dev_err(&spi->dev, "Requested speed is too "
- "low: %d Hz. Will use %d Hz instead.\n",
- spi->max_speed_hz,
- mpc83xx_spi->spibrg / 1024);
- pm = 0x0f;
- }
- regval |= SPMODE_PM(pm) | SPMODE_DIV16;
- } else {
- pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4);
- if (pm)
- pm--;
- regval |= SPMODE_PM(pm);
+ mpc83xx_spi->rx_shift = cs->rx_shift;
+ mpc83xx_spi->tx_shift = cs->tx_shift;
+ mpc83xx_spi->get_rx = cs->get_rx;
+ mpc83xx_spi->get_tx = cs->get_tx;
+
+ if (cs->hw_mode != regval) {
+ unsigned long flags;
+ void *tmp_ptr = &mpc83xx_spi->base->mode;
+
+ regval = cs->hw_mode;
+ /* Turn off IRQs locally to minimize time that
+ * SPI is disabled
+ */
+ local_irq_save(flags);
+ /* Turn off SPI unit prior changing mode */
+ mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
+ mpc83xx_spi_write_reg(tmp_ptr, regval);
+ local_irq_restore(flags);
}
-
- /* Turn off SPI unit prior changing mode */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
if (mpc83xx_spi->activate_cs)
mpc83xx_spi->activate_cs(spi->chip_select, pol);
}
@@ -201,8 +194,9 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc83xx_spi *mpc83xx_spi;
u32 regval;
- u8 bits_per_word;
+ u8 bits_per_word, pm;
u32 hz;
+ struct spi_mpc83xx_cs *cs = spi->controller_state;
mpc83xx_spi = spi_master_get_devdata(spi->master);
@@ -223,61 +217,191 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|| ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL;
- mpc83xx_spi->rx_shift = 0;
- mpc83xx_spi->tx_shift = 0;
+ if (!hz)
+ hz = spi->max_speed_hz;
+
+ cs->rx_shift = 0;
+ cs->tx_shift = 0;
if (bits_per_word <= 8) {
- mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
- mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+ cs->get_rx = mpc83xx_spi_rx_buf_u8;
+ cs->get_tx = mpc83xx_spi_tx_buf_u8;
if (mpc83xx_spi->qe_mode) {
- mpc83xx_spi->rx_shift = 16;
- mpc83xx_spi->tx_shift = 24;
+ cs->rx_shift = 16;
+ cs->tx_shift = 24;
}
} else if (bits_per_word <= 16) {
- mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16;
- mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16;
+ cs->get_rx = mpc83xx_spi_rx_buf_u16;
+ cs->get_tx = mpc83xx_spi_tx_buf_u16;
if (mpc83xx_spi->qe_mode) {
- mpc83xx_spi->rx_shift = 16;
- mpc83xx_spi->tx_shift = 16;
+ cs->rx_shift = 16;
+ cs->tx_shift = 16;
}
} else if (bits_per_word <= 32) {
- mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32;
- mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32;
+ cs->get_rx = mpc83xx_spi_rx_buf_u32;
+ cs->get_tx = mpc83xx_spi_tx_buf_u32;
} else
return -EINVAL;
if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
- mpc83xx_spi->tx_shift = 0;
+ cs->tx_shift = 0;
if (bits_per_word <= 8)
- mpc83xx_spi->rx_shift = 8;
+ cs->rx_shift = 8;
else
- mpc83xx_spi->rx_shift = 0;
+ cs->rx_shift = 0;
}
- /* nsecs = (clock period)/2 */
- if (!hz)
- hz = spi->max_speed_hz;
- mpc83xx_spi->nsecs = (1000000000 / 2) / hz;
- if (mpc83xx_spi->nsecs > MAX_UDELAY_MS * 1000)
- return -EINVAL;
+ mpc83xx_spi->rx_shift = cs->rx_shift;
+ mpc83xx_spi->tx_shift = cs->tx_shift;
+ mpc83xx_spi->get_rx = cs->get_rx;
+ mpc83xx_spi->get_tx = cs->get_tx;
if (bits_per_word == 32)
bits_per_word = 0;
else
bits_per_word = bits_per_word - 1;
- regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
-
/* mask out bits we are going to set */
- regval &= ~(SPMODE_LEN(0xF) | SPMODE_REV);
- regval |= SPMODE_LEN(bits_per_word);
- if (!(spi->mode & SPI_LSB_FIRST))
- regval |= SPMODE_REV;
+ cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
+ | SPMODE_PM(0xF));
+
+ cs->hw_mode |= SPMODE_LEN(bits_per_word);
+
+ if ((mpc83xx_spi->spibrg / hz) >= 64) {
+ pm = mpc83xx_spi->spibrg / (hz * 64) - 1;
+ if (pm > 0x0f) {
+ dev_err(&spi->dev, "Requested speed is too "
+ "low: %d Hz. Will use %d Hz instead.\n",
+ hz, mpc83xx_spi->spibrg / 1024);
+ pm = 0x0f;
+ }
+ cs->hw_mode |= SPMODE_PM(pm) | SPMODE_DIV16;
+ } else {
+ pm = mpc83xx_spi->spibrg / (hz * 4);
+ if (pm)
+ pm--;
+ cs->hw_mode |= SPMODE_PM(pm);
+ }
+ regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+ if (cs->hw_mode != regval) {
+ unsigned long flags;
+ void *tmp_ptr = &mpc83xx_spi->base->mode;
+
+ regval = cs->hw_mode;
+ /* Turn off IRQs locally to minimize time
+ * that SPI is disabled
+ */
+ local_irq_save(flags);
+ /* Turn off SPI unit prior changing mode */
+ mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
+ mpc83xx_spi_write_reg(tmp_ptr, regval);
+ local_irq_restore(flags);
+ }
+ return 0;
+}
- /* Turn off SPI unit prior changing mode */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct mpc83xx_spi *mpc83xx_spi;
+ u32 word, len, bits_per_word;
- return 0;
+ mpc83xx_spi = spi_master_get_devdata(spi->master);
+
+ mpc83xx_spi->tx = t->tx_buf;
+ mpc83xx_spi->rx = t->rx_buf;
+ bits_per_word = spi->bits_per_word;
+ if (t->bits_per_word)
+ bits_per_word = t->bits_per_word;
+ len = t->len;
+ if (bits_per_word > 8)
+ len /= 2;
+ if (bits_per_word > 16)
+ len /= 2;
+ mpc83xx_spi->count = len;
+ INIT_COMPLETION(mpc83xx_spi->done);
+
+ /* enable rx ints */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
+
+ /* transmit word */
+ word = mpc83xx_spi->get_tx(mpc83xx_spi);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
+
+ wait_for_completion(&mpc83xx_spi->done);
+
+ /* disable rx ints */
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
+
+ return mpc83xx_spi->count;
+}
+
+static void mpc83xx_spi_work(struct work_struct *work)
+{
+ struct mpc83xx_spi *mpc83xx_spi =
+ container_of(work, struct mpc83xx_spi, work);
+
+ spin_lock_irq(&mpc83xx_spi->lock);
+ mpc83xx_spi->busy = 1;
+ while (!list_empty(&mpc83xx_spi->queue)) {
+ struct spi_message *m;
+ struct spi_device *spi;
+ struct spi_transfer *t = NULL;
+ unsigned cs_change;
+ int status, nsecs = 50;
+
+ m = container_of(mpc83xx_spi->queue.next,
+ struct spi_message, queue);
+ list_del_init(&m->queue);
+ spin_unlock_irq(&mpc83xx_spi->lock);
+
+ spi = m->spi;
+ cs_change = 1;
+ status = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->bits_per_word || t->speed_hz) {
+ /* Don't allow changes if CS is active */
+ status = -EINVAL;
+
+ if (cs_change)
+ status = mpc83xx_spi_setup_transfer(spi, t);
+ if (status < 0)
+ break;
+ }
+
+ if (cs_change)
+ mpc83xx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+ cs_change = t->cs_change;
+ if (t->len)
+ status = mpc83xx_spi_bufs(spi, t);
+ if (status) {
+ status = -EMSGSIZE;
+ break;
+ }
+ m->actual_length += t->len;
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (cs_change) {
+ ndelay(nsecs);
+ mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(nsecs);
+ }
+ }
+
+ m->status = status;
+ m->complete(m->context);
+
+ if (status || !cs_change) {
+ ndelay(nsecs);
+ mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+ }
+
+ mpc83xx_spi_setup_transfer(spi, NULL);
+
+ spin_lock_irq(&mpc83xx_spi->lock);
+ }
+ mpc83xx_spi->busy = 0;
+ spin_unlock_irq(&mpc83xx_spi->lock);
}
/* the spi->mode bits understood by this driver: */
@@ -286,9 +410,10 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static int mpc83xx_spi_setup(struct spi_device *spi)
{
- struct spi_bitbang *bitbang;
struct mpc83xx_spi *mpc83xx_spi;
int retval;
+ u32 hw_mode;
+ struct spi_mpc83xx_cs *cs = spi->controller_state;
if (spi->mode & ~MODEBITS) {
dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
@@ -299,63 +424,56 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
if (!spi->max_speed_hz)
return -EINVAL;
- bitbang = spi_master_get_devdata(spi->master);
+ if (!cs) {
+ cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ spi->controller_state = cs;
+ }
mpc83xx_spi = spi_master_get_devdata(spi->master);
if (!spi->bits_per_word)
spi->bits_per_word = 8;
+ hw_mode = cs->hw_mode; /* Save orginal settings */
+ cs->hw_mode = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
+ /* mask out bits we are going to set */
+ cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
+ | SPMODE_REV | SPMODE_LOOP);
+
+ if (spi->mode & SPI_CPHA)
+ cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
+ if (spi->mode & SPI_CPOL)
+ cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
+ if (!(spi->mode & SPI_LSB_FIRST))
+ cs->hw_mode |= SPMODE_REV;
+ if (spi->mode & SPI_LOOP)
+ cs->hw_mode |= SPMODE_LOOP;
+
retval = mpc83xx_spi_setup_transfer(spi, NULL);
- if (retval < 0)
+ if (retval < 0) {
+ cs->hw_mode = hw_mode; /* Restore settings */
return retval;
+ }
- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u Hz\n",
__func__, spi->mode & (SPI_CPOL | SPI_CPHA),
- spi->bits_per_word, 2 * mpc83xx_spi->nsecs);
-
+ spi->bits_per_word, spi->max_speed_hz);
+#if 0 /* Don't think this is needed */
/* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup, unless the hardware defaults cooperate to avoid confusion
* between normal (active low) and inverted chipselects.
*/
/* deselect chip (low or high) */
- spin_lock(&bitbang->lock);
- if (!bitbang->busy) {
- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
- ndelay(mpc83xx_spi->nsecs);
- }
- spin_unlock(&bitbang->lock);
-
+ spin_lock(&mpc83xx_spi->lock);
+ if (!mpc83xx_spi->busy)
+ mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+ spin_unlock(&mpc83xx_spi->lock);
+#endif
return 0;
}
-static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
-{
- struct mpc83xx_spi *mpc83xx_spi;
- u32 word;
-
- mpc83xx_spi = spi_master_get_devdata(spi->master);
-
- mpc83xx_spi->tx = t->tx_buf;
- mpc83xx_spi->rx = t->rx_buf;
- mpc83xx_spi->count = t->len;
- INIT_COMPLETION(mpc83xx_spi->done);
-
- /* enable rx ints */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
-
- /* transmit word */
- word = mpc83xx_spi->get_tx(mpc83xx_spi);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
-
- wait_for_completion(&mpc83xx_spi->done);
-
- /* disable rx ints */
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
-
- return t->len - mpc83xx_spi->count;
-}
-
irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
{
struct mpc83xx_spi *mpc83xx_spi = context_data;
@@ -395,6 +513,28 @@ irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
return ret;
}
+static int mpc83xx_spi_transfer(struct spi_device *spi,
+ struct spi_message *m)
+{
+ struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ m->actual_length = 0;
+ m->status = -EINPROGRESS;
+
+ spin_lock_irqsave(&mpc83xx_spi->lock, flags);
+ list_add_tail(&m->queue, &mpc83xx_spi->queue);
+ queue_work(mpc83xx_spi->workqueue, &mpc83xx_spi->work);
+ spin_unlock_irqrestore(&mpc83xx_spi->lock, flags);
+
+ return 0;
+}
+
+
+static void mpc83xx_spi_cleanup(struct spi_device *spi)
+{
+ kfree(spi->controller_state);
+}
static int __init mpc83xx_spi_probe(struct platform_device *dev)
{
@@ -426,11 +566,11 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
ret = -ENODEV;
goto free_master;
}
+ master->setup = mpc83xx_spi_setup;
+ master->transfer = mpc83xx_spi_transfer;
+ master->cleanup = mpc83xx_spi_cleanup;
+
mpc83xx_spi = spi_master_get_devdata(master);
- mpc83xx_spi->bitbang.master = spi_master_get(master);
- mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
- mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
- mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
mpc83xx_spi->activate_cs = pdata->activate_cs;
mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
mpc83xx_spi->qe_mode = pdata->qe_mode;
@@ -445,7 +585,6 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->tx_shift = 24;
}
- mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
init_completion(&mpc83xx_spi->done);
mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
@@ -483,11 +622,21 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
regval |= SPMODE_OP;
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
+ spin_lock_init(&mpc83xx_spi->lock);
+ init_completion(&mpc83xx_spi->done);
+ INIT_WORK(&mpc83xx_spi->work, mpc83xx_spi_work);
+ INIT_LIST_HEAD(&mpc83xx_spi->queue);
- ret = spi_bitbang_start(&mpc83xx_spi->bitbang);
-
- if (ret != 0)
+ mpc83xx_spi->workqueue = create_singlethread_workqueue(
+ master->dev.parent->bus_id);
+ if (mpc83xx_spi->workqueue == NULL) {
+ ret = -EBUSY;
goto free_irq;
+ }
+
+ ret = spi_register_master(master);
+ if (ret < 0)
+ goto unreg_master;
printk(KERN_INFO
"%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
@@ -495,6 +644,8 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
return ret;
+unreg_master:
+ destroy_workqueue(mpc83xx_spi->workqueue);
free_irq:
free_irq(mpc83xx_spi->irq, mpc83xx_spi);
unmap_io:
@@ -515,10 +666,12 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev)
master = platform_get_drvdata(dev);
mpc83xx_spi = spi_master_get_devdata(master);
- spi_bitbang_stop(&mpc83xx_spi->bitbang);
+ flush_workqueue(mpc83xx_spi->workqueue);
+ destroy_workqueue(mpc83xx_spi->workqueue);
+ spi_unregister_master(master);
+
free_irq(mpc83xx_spi->irq, mpc83xx_spi);
iounmap(mpc83xx_spi->base);
- spi_master_put(mpc83xx_spi->bitbang.master);
return 0;
}
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 34bfb7dd7764..0885cc357a37 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -125,10 +125,10 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi,
/* is clk = pclk / (2 * (pre+1)), or is it
* clk = (pclk * 2) / ( pre + 1) */
- div = (div / 2) - 1;
+ div /= 2;
- if (div < 0)
- div = 1;
+ if (div > 0)
+ div -= 1;
if (div > 255)
div = 255;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 17e71d56f31e..4b628526df09 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig THERMAL
- bool "Generic Thermal sysfs driver"
+ tristate "Generic Thermal sysfs driver"
help
Generic Thermal Sysfs driver offers a generic mechanism for
thermal management. Usually it's made up of one or more thermal
@@ -11,4 +11,4 @@ menuconfig THERMAL
Each thermal zone contains its own temperature, trip points,
cooling devices.
All platforms with ACPI thermal support can use this driver.
- If you want this support, you should say Y here.
+ If you want this support, you should say Y or M here.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 8ef1232de376..31108a01c22e 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -2,4 +2,4 @@
# Makefile for sensor chip drivers.
#
-obj-$(CONFIG_THERMAL) += thermal.o
+obj-$(CONFIG_THERMAL) += thermal_sys.o
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal_sys.c
index 7f79bbf652d7..6098787341f3 100644
--- a/drivers/thermal/thermal.c
+++ b/drivers/thermal/thermal_sys.c
@@ -31,7 +31,7 @@
#include <linux/thermal.h>
#include <linux/spinlock.h>
-MODULE_AUTHOR("Zhang Rui")
+MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL");
@@ -295,6 +295,164 @@ thermal_cooling_device_trip_point_show(struct device *dev,
/* Device management */
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* hwmon sys I/F */
+#include <linux/hwmon.h>
+static LIST_HEAD(thermal_hwmon_list);
+
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_hwmon_device *hwmon = dev->driver_data;
+ return sprintf(buf, "%s\n", hwmon->type);
+}
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+ struct thermal_zone_device *tz
+ = container_of(hwmon_attr, struct thermal_zone_device,
+ temp_input);
+
+ return tz->ops->get_temp(tz, buf);
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+ struct thermal_zone_device *tz
+ = container_of(hwmon_attr, struct thermal_zone_device,
+ temp_crit);
+
+ return tz->ops->get_trip_temp(tz, 0, buf);
+}
+
+
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ struct thermal_hwmon_device *hwmon;
+ int new_hwmon_device = 1;
+ int result;
+
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(hwmon, &thermal_hwmon_list, node)
+ if (!strcmp(hwmon->type, tz->type)) {
+ new_hwmon_device = 0;
+ mutex_unlock(&thermal_list_lock);
+ goto register_sys_interface;
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&hwmon->tz_list);
+ strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
+ hwmon->device = hwmon_device_register(NULL);
+ if (IS_ERR(hwmon->device)) {
+ result = PTR_ERR(hwmon->device);
+ goto free_mem;
+ }
+ hwmon->device->driver_data = hwmon;
+ result = device_create_file(hwmon->device, &dev_attr_name);
+ if (result)
+ goto unregister_hwmon_device;
+
+ register_sys_interface:
+ tz->hwmon = hwmon;
+ hwmon->count++;
+
+ snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
+ "temp%d_input", hwmon->count);
+ tz->temp_input.attr.attr.name = tz->temp_input.name;
+ tz->temp_input.attr.attr.mode = 0444;
+ tz->temp_input.attr.show = temp_input_show;
+ result = device_create_file(hwmon->device, &tz->temp_input.attr);
+ if (result)
+ goto unregister_hwmon_device;
+
+ if (tz->ops->get_crit_temp) {
+ unsigned long temperature;
+ if (!tz->ops->get_crit_temp(tz, &temperature)) {
+ snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
+ "temp%d_crit", hwmon->count);
+ tz->temp_crit.attr.attr.name = tz->temp_crit.name;
+ tz->temp_crit.attr.attr.mode = 0444;
+ tz->temp_crit.attr.show = temp_crit_show;
+ result = device_create_file(hwmon->device,
+ &tz->temp_crit.attr);
+ if (result)
+ goto unregister_hwmon_device;
+ }
+ }
+
+ mutex_lock(&thermal_list_lock);
+ if (new_hwmon_device)
+ list_add_tail(&hwmon->node, &thermal_hwmon_list);
+ list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
+ mutex_unlock(&thermal_list_lock);
+
+ return 0;
+
+ unregister_hwmon_device:
+ device_remove_file(hwmon->device, &tz->temp_crit.attr);
+ device_remove_file(hwmon->device, &tz->temp_input.attr);
+ if (new_hwmon_device) {
+ device_remove_file(hwmon->device, &dev_attr_name);
+ hwmon_device_unregister(hwmon->device);
+ }
+ free_mem:
+ if (new_hwmon_device)
+ kfree(hwmon);
+
+ return result;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ struct thermal_hwmon_device *hwmon = tz->hwmon;
+
+ tz->hwmon = NULL;
+ device_remove_file(hwmon->device, &tz->temp_input.attr);
+ device_remove_file(hwmon->device, &tz->temp_crit.attr);
+
+ mutex_lock(&thermal_list_lock);
+ list_del(&tz->hwmon_node);
+ if (!list_empty(&hwmon->tz_list)) {
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+ list_del(&hwmon->node);
+ mutex_unlock(&thermal_list_lock);
+
+ device_remove_file(hwmon->device, &dev_attr_name);
+ hwmon_device_unregister(hwmon->device);
+ kfree(hwmon);
+}
+#else
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ return 0;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+}
+#endif
+
+
/**
* thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
* @tz: thermal zone device
@@ -642,6 +800,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
goto unregister;
}
+ result = thermal_add_hwmon_sysfs(tz);
+ if (result)
+ goto unregister;
+
mutex_lock(&thermal_list_lock);
list_add_tail(&tz->node, &thermal_tz_list);
if (ops->bind)
@@ -700,6 +862,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
for (count = 0; count < tz->trips; count++)
TRIP_POINT_ATTR_REMOVE(&tz->device, count);
+ thermal_remove_hwmon_sysfs(tz);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 516a6400db43..a419c42e880e 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
+obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
+
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 86e64035edb0..be0b8daac9c7 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -19,7 +19,6 @@ if USB_ATM
config USB_SPEEDTOUCH
tristate "Speedtouch USB support"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an SpeedTouch USB or SpeedTouch 330
@@ -32,7 +31,6 @@ config USB_SPEEDTOUCH
config USB_CXACRU
tristate "Conexant AccessRunner USB support"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the Conexant
@@ -45,7 +43,6 @@ config USB_CXACRU
config USB_UEAGLEATM
tristate "ADI 930 and eagle USB DSL modem"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the ADI 930
@@ -58,7 +55,6 @@ config USB_UEAGLEATM
config USB_XUSBATM
tristate "Other USB DSL modem support"
- depends on USB_ATM
help
Say Y here if you have a DSL USB modem not explicitly supported by
another USB DSL drivers. In order to use your modem you will need to
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 4220f22b6660..5f71ff3aee35 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -305,8 +305,6 @@ enum {
*/
#define FW_GET_BYTE(p) *((__u8 *) (p))
-#define FW_GET_WORD(p) le16_to_cpu(get_unaligned((__le16 *) (p)))
-#define FW_GET_LONG(p) le32_to_cpu(get_unaligned((__le32 *) (p)))
#define FW_DIR "ueagle-atm/"
#define NB_MODEM 4
@@ -621,7 +619,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte
if (size < 4)
goto err_fw_corrupted;
- crc = FW_GET_LONG(pfw);
+ crc = get_unaligned_le32(pfw);
pfw += 4;
size -= 4;
if (crc32_be(0, pfw, size) != crc)
@@ -640,7 +638,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte
while (size > 3) {
u8 len = FW_GET_BYTE(pfw);
- u16 add = FW_GET_WORD(pfw + 1);
+ u16 add = get_unaligned_le16(pfw + 1);
size -= len + 3;
if (size < 0)
@@ -738,7 +736,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len)
for (i = 0; i < pagecount; i++) {
- pageoffset = FW_GET_LONG(dsp + p);
+ pageoffset = get_unaligned_le32(dsp + p);
p += 4;
if (pageoffset == 0)
@@ -759,7 +757,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len)
return 1;
pp += 2; /* skip blockaddr */
- blocksize = FW_GET_WORD(dsp + pp);
+ blocksize = get_unaligned_le16(dsp + pp);
pp += 2;
/* enough space for block data? */
@@ -928,7 +926,7 @@ static void uea_load_page_e1(struct work_struct *work)
goto bad1;
p += 4 * pageno;
- pageoffset = FW_GET_LONG(p);
+ pageoffset = get_unaligned_le32(p);
if (pageoffset == 0)
goto bad1;
@@ -945,10 +943,10 @@ static void uea_load_page_e1(struct work_struct *work)
bi.wOvlOffset = cpu_to_le16(ovl | 0x8000);
for (i = 0; i < blockcount; i++) {
- blockaddr = FW_GET_WORD(p);
+ blockaddr = get_unaligned_le16(p);
p += 2;
- blocksize = FW_GET_WORD(p);
+ blocksize = get_unaligned_le16(p);
p += 2;
bi.wSize = cpu_to_le16(blocksize);
@@ -1152,9 +1150,9 @@ static int uea_cmv_e1(struct uea_softc *sc,
cmv.bDirection = E1_HOSTTOMODEM;
cmv.bFunction = function;
cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
- put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
+ put_unaligned_le32(address, &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
- put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
+ put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData);
ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
if (ret < 0)
@@ -1646,7 +1644,7 @@ static int request_cmvs(struct uea_softc *sc,
if (size < 5)
goto err_fw_corrupted;
- crc = FW_GET_LONG(data);
+ crc = get_unaligned_le32(data);
data += 4;
size -= 4;
if (crc32_be(0, data, size) != crc)
@@ -1696,9 +1694,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
"please update your firmware\n");
for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
- FW_GET_WORD(&cmvs_v1[i].offset),
- FW_GET_LONG(&cmvs_v1[i].data));
+ ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address),
+ get_unaligned_le16(&cmvs_v1[i].offset),
+ get_unaligned_le32(&cmvs_v1[i].data));
if (ret < 0)
goto out;
}
@@ -1706,9 +1704,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
- (u16) FW_GET_LONG(&cmvs_v2[i].offset),
- FW_GET_LONG(&cmvs_v2[i].data));
+ ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address),
+ (u16) get_unaligned_le32(&cmvs_v2[i].offset),
+ get_unaligned_le32(&cmvs_v2[i].data));
if (ret < 0)
goto out;
}
@@ -1759,10 +1757,10 @@ static int uea_send_cmvs_e4(struct uea_softc *sc)
for (i = 0; i < len; i++) {
ret = uea_write_cmv_e4(sc, 1,
- FW_GET_LONG(&cmvs_v2[i].group),
- FW_GET_LONG(&cmvs_v2[i].address),
- FW_GET_LONG(&cmvs_v2[i].offset),
- FW_GET_LONG(&cmvs_v2[i].data));
+ get_unaligned_le32(&cmvs_v2[i].group),
+ get_unaligned_le32(&cmvs_v2[i].address),
+ get_unaligned_le32(&cmvs_v2[i].offset),
+ get_unaligned_le32(&cmvs_v2[i].data));
if (ret < 0)
goto out;
}
@@ -1964,7 +1962,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
if (UEA_CHIP_VERSION(sc) == ADI930
&& cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
cmv->wIndex = cpu_to_le16(dsc->idx);
- put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+ put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress);
cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
} else
goto bad2;
@@ -1978,11 +1976,11 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
/* in case of MEMACCESS */
if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+ get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address ||
le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
goto bad2;
- sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
+ sc->data = get_unaligned_le32(&cmv->dwData);
sc->data = sc->data << 16 | sc->data >> 16;
wake_up_cmv_ack(sc);
diff --git a/drivers/usb/c67x00/Makefile b/drivers/usb/c67x00/Makefile
new file mode 100644
index 000000000000..868bc41b5980
--- /dev/null
+++ b/drivers/usb/c67x00/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for Cypress C67X00 USB Controller
+#
+
+ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o
+
+c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
new file mode 100644
index 000000000000..5633bc5c8bf2
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -0,0 +1,243 @@
+/*
+ * c67x00-drv.c: Cypress C67X00 USB Common infrastructure
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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.
+ */
+
+/*
+ * This file implements the common infrastructure for using the c67x00.
+ * It is both the link between the platform configuration and subdrivers and
+ * the link between the common hardware parts and the subdrivers (e.g.
+ * interrupt handling).
+ *
+ * The c67x00 has 2 SIE's (serial interface engine) wich can be configured
+ * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
+ *
+ * Depending on the platform configuration, the SIE's are created and
+ * the corresponding subdriver is initialized (c67x00_probe_sie).
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+static void c67x00_probe_sie(struct c67x00_sie *sie,
+ struct c67x00_device *dev, int sie_num)
+{
+ spin_lock_init(&sie->lock);
+ sie->dev = dev;
+ sie->sie_num = sie_num;
+ sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
+
+ switch (sie->mode) {
+ case C67X00_SIE_HOST:
+ c67x00_hcd_probe(sie);
+ break;
+
+ case C67X00_SIE_UNUSED:
+ dev_info(sie_dev(sie),
+ "Not using SIE %d as requested\n", sie->sie_num);
+ break;
+
+ default:
+ dev_err(sie_dev(sie),
+ "Unsupported configuration: 0x%x for SIE %d\n",
+ sie->mode, sie->sie_num);
+ break;
+ }
+}
+
+static void c67x00_remove_sie(struct c67x00_sie *sie)
+{
+ switch (sie->mode) {
+ case C67X00_SIE_HOST:
+ c67x00_hcd_remove(sie);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static irqreturn_t c67x00_irq(int irq, void *__dev)
+{
+ struct c67x00_device *c67x00 = __dev;
+ struct c67x00_sie *sie;
+ u16 msg, int_status;
+ int i, count = 8;
+
+ int_status = c67x00_ll_hpi_status(c67x00);
+ if (!int_status)
+ return IRQ_NONE;
+
+ while (int_status != 0 && (count-- >= 0)) {
+ c67x00_ll_irq(c67x00, int_status);
+ for (i = 0; i < C67X00_SIES; i++) {
+ sie = &c67x00->sie[i];
+ msg = 0;
+ if (int_status & SIEMSG_FLG(i))
+ msg = c67x00_ll_fetch_siemsg(c67x00, i);
+ if (sie->irq)
+ sie->irq(sie, int_status, msg);
+ }
+ int_status = c67x00_ll_hpi_status(c67x00);
+ }
+
+ if (int_status)
+ dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
+ "status = 0x%04x\n", int_status);
+
+ return IRQ_HANDLED;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit c67x00_drv_probe(struct platform_device *pdev)
+{
+ struct c67x00_device *c67x00;
+ struct c67x00_platform_data *pdata;
+ struct resource *res, *res2;
+ int ret, i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL);
+ if (!c67x00)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+ c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+ if (!c67x00->hpi.base) {
+ dev_err(&pdev->dev, "Unable to map HPI registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ spin_lock_init(&c67x00->hpi.lock);
+ c67x00->hpi.regstep = pdata->hpi_regstep;
+ c67x00->pdata = pdev->dev.platform_data;
+ c67x00->pdev = pdev;
+
+ c67x00_ll_init(c67x00);
+ c67x00_ll_hpi_reg_init(c67x00);
+
+ ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ ret = c67x00_ll_reset(c67x00);
+ if (ret) {
+ dev_err(&pdev->dev, "Device reset failed\n");
+ goto reset_failed;
+ }
+
+ for (i = 0; i < C67X00_SIES; i++)
+ c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
+
+ platform_set_drvdata(pdev, c67x00);
+
+ return 0;
+
+ reset_failed:
+ free_irq(res2->start, c67x00);
+ request_irq_failed:
+ iounmap(c67x00->hpi.base);
+ map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+ kfree(c67x00);
+
+ return ret;
+}
+
+static int __devexit c67x00_drv_remove(struct platform_device *pdev)
+{
+ struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
+ struct resource *res;
+ int i;
+
+ for (i = 0; i < C67X00_SIES; i++)
+ c67x00_remove_sie(&c67x00->sie[i]);
+
+ c67x00_ll_release(c67x00);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, c67x00);
+
+ iounmap(c67x00->hpi.base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(c67x00);
+
+ return 0;
+}
+
+static struct platform_driver c67x00_driver = {
+ .probe = c67x00_drv_probe,
+ .remove = __devexit_p(c67x00_drv_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "c67x00",
+ },
+};
+MODULE_ALIAS("platform:c67x00");
+
+static int __init c67x00_init(void)
+{
+ return platform_driver_register(&c67x00_driver);
+}
+
+static void __exit c67x00_exit(void)
+{
+ platform_driver_unregister(&c67x00_driver);
+}
+
+module_init(c67x00_init);
+module_exit(c67x00_exit);
+
+MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
+MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c
new file mode 100644
index 000000000000..a22b887f4e9e
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-hcd.c
@@ -0,0 +1,412 @@
+/*
+ * c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/device.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/* --------------------------------------------------------------------------
+ * Root Hub Support
+ */
+
+static __u8 c67x00_hub_des[] = {
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
+ 0x32, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; ** 7 Ports max ** */
+ 0xff, /* __u8 PortPwrCtrlMask; ** 7 ports max ** */
+};
+
+static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ unsigned long flags;
+
+ c67x00_ll_husb_reset(sie, port);
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ c67x00_ll_husb_reset_port(sie, port);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT);
+}
+
+static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ struct c67x00_sie *sie = c67x00->sie;
+ u16 status;
+ int i;
+
+ *buf = 0;
+ status = c67x00_ll_usb_get_status(sie);
+ for (i = 0; i < C67X00_PORTS; i++)
+ if (status & PORT_CONNECT_CHANGE(i))
+ *buf |= (1 << i);
+
+ /* bit 0 denotes hub change, b1..n port change */
+ *buf <<= 1;
+
+ return !!*buf;
+}
+
+static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ struct c67x00_sie *sie = c67x00->sie;
+ u16 status, usb_status;
+ int len = 0;
+ unsigned int port = wIndex-1;
+ u16 wPortChange, wPortStatus;
+
+ switch (typeReq) {
+
+ case GetHubStatus:
+ *(__le32 *) buf = cpu_to_le32(0);
+ len = 4; /* hub power */
+ break;
+
+ case GetPortStatus:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ status = c67x00_ll_usb_get_status(sie);
+ usb_status = c67x00_ll_get_usb_ctl(sie);
+
+ wPortChange = 0;
+ if (status & PORT_CONNECT_CHANGE(port))
+ wPortChange |= USB_PORT_STAT_C_CONNECTION;
+
+ wPortStatus = USB_PORT_STAT_POWER;
+ if (!(status & PORT_SE0_STATUS(port)))
+ wPortStatus |= USB_PORT_STAT_CONNECTION;
+ if (usb_status & LOW_SPEED_PORT(port)) {
+ wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+ c67x00->low_speed_ports |= (1 << port);
+ } else
+ c67x00->low_speed_ports &= ~(1 << port);
+
+ if (usb_status & SOF_EOP_EN(port))
+ wPortStatus |= USB_PORT_STAT_ENABLE;
+
+ *(__le16 *) buf = cpu_to_le16(wPortStatus);
+ *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
+ len = 4;
+ break;
+
+ case SetHubFeature: /* We don't implement these */
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ len = 0;
+ break;
+
+ default:
+ return -EPIPE;
+ }
+ break;
+
+ case SetPortFeature:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "SetPortFeature %d (SUSPEND)\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_RESET:
+ c67x00_hub_reset_host_port(sie, port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ /* Power always enabled */
+ len = 0;
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "%s: SetPortFeature %d (0x%04x) Error!\n",
+ __func__, port, wValue);
+ return -EPIPE;
+ }
+ break;
+
+ case ClearPortFeature:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ /* Reset the port so that the c67x00 also notices the
+ * disconnect */
+ c67x00_hub_reset_host_port(sie, port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_ENABLE:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_ENABLE\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): SUSPEND\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_SUSPEND\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): POWER\n", port);
+ return -EPIPE;
+
+ case USB_PORT_FEAT_C_CONNECTION:
+ c67x00_ll_usb_clear_status(sie,
+ PORT_CONNECT_CHANGE(port));
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): OVER_CURRENT\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_RESET:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_RESET\n", port);
+ len = 0;
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "%s: ClearPortFeature %d (0x%04x) Error!\n",
+ __func__, port, wValue);
+ return -EPIPE;
+ }
+ break;
+
+ case GetHubDescriptor:
+ len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
+ memcpy(buf, c67x00_hub_des, len);
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__);
+ return -EPIPE;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Main part of host controller driver
+ */
+
+/**
+ * c67x00_hcd_irq
+ *
+ * This function is called from the interrupt handler in c67x00-drv.c
+ */
+static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+ /* Handle sie message flags */
+ if (msg) {
+ if (msg & HUSB_TDListDone)
+ c67x00_sched_kick(c67x00);
+ else
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "Unknown SIE msg flag(s): 0x%04x\n", msg);
+ }
+
+ if (unlikely(hcd->state == HC_STATE_HALT))
+ return;
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ return;
+
+ /* Handle Start of frame events */
+ if (int_status & SOFEOP_FLG(sie->sie_num)) {
+ c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+ c67x00_sched_kick(c67x00);
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+ }
+}
+
+/**
+ * c67x00_hcd_start: Host controller start hook
+ */
+static int c67x00_hcd_start(struct usb_hcd *hcd)
+{
+ hcd->uses_new_polling = 1;
+ hcd->state = HC_STATE_RUNNING;
+ hcd->poll_rh = 1;
+
+ return 0;
+}
+
+/**
+ * c67x00_hcd_stop: Host controller stop hook
+ */
+static void c67x00_hcd_stop(struct usb_hcd *hcd)
+{
+ /* Nothing to do */
+}
+
+static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ u16 temp_val;
+
+ dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__);
+ temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
+ temp_val &= HOST_FRAME_MASK;
+ return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
+}
+
+static struct hc_driver c67x00_hc_driver = {
+ .description = "c67x00-hcd",
+ .product_desc = "Cypress C67X00 Host Controller",
+ .hcd_priv_size = sizeof(struct c67x00_hcd),
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = c67x00_hcd_start,
+ .stop = c67x00_hcd_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = c67x00_urb_enqueue,
+ .urb_dequeue = c67x00_urb_dequeue,
+ .endpoint_disable = c67x00_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = c67x00_hcd_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = c67x00_hub_status_data,
+ .hub_control = c67x00_hub_control,
+};
+
+/* ---------------------------------------------------------------------
+ * Setup/Teardown routines
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+ struct c67x00_hcd *c67x00;
+ struct usb_hcd *hcd;
+ unsigned long flags;
+ int retval;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err0;
+ }
+ c67x00 = hcd_to_c67x00_hcd(hcd);
+
+ spin_lock_init(&c67x00->lock);
+ c67x00->sie = sie;
+
+ INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]);
+ c67x00->urb_count = 0;
+ INIT_LIST_HEAD(&c67x00->td_list);
+ c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num);
+ c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
+ c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+
+ c67x00_ll_husb_init_host_port(sie);
+
+ init_completion(&c67x00->endpoint_disable);
+ retval = c67x00_sched_start_scheduler(c67x00);
+ if (retval)
+ goto err1;
+
+ retval = usb_add_hcd(hcd, 0, 0);
+ if (retval) {
+ dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n",
+ __func__, retval);
+ goto err2;
+ }
+
+ spin_lock_irqsave(&sie->lock, flags);
+ sie->private_data = c67x00;
+ sie->irq = c67x00_hcd_irq;
+ spin_unlock_irqrestore(&sie->lock, flags);
+
+ return retval;
+
+ err2:
+ c67x00_sched_stop_scheduler(c67x00);
+ err1:
+ usb_put_hcd(hcd);
+ err0:
+ return retval;
+}
+
+/* may be called with controller, bus, and devices active */
+void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+ c67x00_sched_stop_scheduler(c67x00);
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+}
diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h
new file mode 100644
index 000000000000..e8c6d94b2514
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-hcd.h
@@ -0,0 +1,133 @@
+/*
+ * c67x00-hcd.h: Cypress C67X00 USB HCD
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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.
+ */
+
+#ifndef _USB_C67X00_HCD_H
+#define _USB_C67X00_HCD_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include "../core/hcd.h"
+#include "c67x00.h"
+
+/*
+ * The following parameters depend on the CPU speed, bus speed, ...
+ * These can be tuned for specific use cases, e.g. if isochronous transfers
+ * are very important, bandwith can be sacrificed to guarantee that the
+ * 1ms deadline will be met.
+ * If bulk transfers are important, the MAX_FRAME_BW can be increased,
+ * but some (or many) isochronous deadlines might not be met.
+ *
+ * The values are specified in bittime.
+ */
+
+/*
+ * The current implementation switches between _STD (default) and _ISO (when
+ * isochronous transfers are scheduled), in order to optimize the throughput
+ * in normal cicrumstances, but also provide good isochronous behaviour.
+ *
+ * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms
+ * frames; there are 12000 bit times per frame.
+ */
+
+#define TOTAL_FRAME_BW 12000
+#define DEFAULT_EOT 2250
+
+#define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT)
+#define MAX_FRAME_BW_ISO 2400
+
+/*
+ * Periodic transfers may only use 90% of the full frame, but as
+ * we currently don't even use 90% of the full frame, we may
+ * use the full usable time for periodic transfers.
+ */
+#define MAX_PERIODIC_BW(full_bw) full_bw
+
+/* -------------------------------------------------------------------------- */
+
+struct c67x00_hcd {
+ spinlock_t lock;
+ struct c67x00_sie *sie;
+ unsigned int low_speed_ports; /* bitmask of low speed ports */
+ unsigned int urb_count;
+ unsigned int urb_iso_count;
+
+ struct list_head list[4]; /* iso, int, ctrl, bulk */
+#if PIPE_BULK != 3
+#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3"
+#endif
+
+ /* USB bandwidth allocated to td_list */
+ int bandwidth_allocated;
+ /* USB bandwidth allocated for isoc/int transfer */
+ int periodic_bw_allocated;
+ struct list_head td_list;
+ int max_frame_bw;
+
+ u16 td_base_addr;
+ u16 buf_base_addr;
+ u16 next_td_addr;
+ u16 next_buf_addr;
+
+ struct tasklet_struct tasklet;
+
+ struct completion endpoint_disable;
+
+ u16 current_frame;
+ u16 last_frame;
+};
+
+static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd)
+{
+ return (struct c67x00_hcd *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00)
+{
+ return container_of((void *)c67x00, struct usb_hcd, hcd_priv);
+}
+
+/* ---------------------------------------------------------------------
+ * Functions used by c67x00-drv
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie);
+void c67x00_hcd_remove(struct c67x00_sie *sie);
+
+/* ---------------------------------------------------------------------
+ * Transfer Descriptor scheduling functions
+ */
+int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+void c67x00_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep);
+
+void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg);
+void c67x00_sched_kick(struct c67x00_hcd *c67x00);
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00);
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00);
+
+#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller)
+
+#endif /* _USB_C67X00_HCD_H */
diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c
new file mode 100644
index 000000000000..5100fbbf6cb0
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -0,0 +1,481 @@
+/*
+ * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/usb/c67x00.h>
+#include "c67x00.h"
+
+#define COMM_REGS 14
+
+struct c67x00_lcp_int_data {
+ u16 regs[COMM_REGS];
+};
+
+/* -------------------------------------------------------------------------- */
+/* Interface definitions */
+
+#define COMM_ACK 0x0FED
+#define COMM_NAK 0xDEAD
+
+#define COMM_RESET 0xFA50
+#define COMM_EXEC_INT 0xCE01
+#define COMM_INT_NUM 0x01C2
+
+/* Registers 0 to COMM_REGS-1 */
+#define COMM_R(x) (0x01C4 + 2 * (x))
+
+#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0)
+#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6)
+#define HUSB_pEOT 0x01B4
+
+/* Software interrupts */
+/* 114, 115: */
+#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072)
+#define HUSB_RESET_INT 0x0074
+
+#define SUSB_INIT_INT 0x0071
+#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2)
+
+/* -----------------------------------------------------------------------
+ * HPI implementation
+ *
+ * The c67x00 chip also support control via SPI or HSS serial
+ * interfaces. However, this driver assumes that register access can
+ * be performed from IRQ context. While this is a safe assuption with
+ * the HPI interface, it is not true for the serial interfaces.
+ */
+
+/* HPI registers */
+#define HPI_DATA 0
+#define HPI_MAILBOX 1
+#define HPI_ADDR 2
+#define HPI_STATUS 3
+
+static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
+{
+ return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
+{
+ __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
+{
+ hpi_write_reg(dev, HPI_ADDR, reg);
+ return hpi_read_reg(dev, HPI_DATA);
+}
+
+static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
+{
+ hpi_write_reg(dev, HPI_ADDR, reg);
+ hpi_write_reg(dev, HPI_DATA, value);
+}
+
+static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_word_nolock(dev, reg, value);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
+ u16 *data, u16 count)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+
+ hpi_write_reg(dev, HPI_ADDR, addr);
+ for (i = 0; i < count; i++)
+ hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
+
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
+ u16 *data, u16 count)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_reg(dev, HPI_ADDR, addr);
+ for (i = 0; i < count; i++)
+ *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
+
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ hpi_write_word_nolock(dev, reg, value | mask);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ hpi_write_word_nolock(dev, reg, value & ~mask);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static u16 hpi_recv_mbox(struct c67x00_device *dev)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_reg(dev, HPI_MAILBOX);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_reg(dev, HPI_MAILBOX, value);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_reg(dev, HPI_STATUS);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
+{
+ int i;
+
+ hpi_recv_mbox(dev);
+ c67x00_ll_hpi_status(dev);
+ hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
+
+ for (i = 0; i < C67X00_SIES; i++) {
+ hpi_write_word(dev, SIEMSG_REG(i), 0);
+ hpi_read_word(dev, SIEMSG_REG(i));
+ }
+}
+
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
+{
+ hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
+{
+ hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+/* Transactions */
+
+static inline u16 ll_recv_msg(struct c67x00_device *dev)
+{
+ u16 res;
+
+ res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
+ WARN_ON(!res);
+
+ return (res == 0) ? -EIO : 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* General functions */
+
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
+{
+ u16 val;
+
+ val = hpi_read_word(dev, SIEMSG_REG(sie_num));
+ /* clear register to allow next message */
+ hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
+
+ return val;
+}
+
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+}
+
+/**
+ * c67x00_ll_usb_clear_status - clear the USB status bits
+ */
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
+{
+ hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
+}
+
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
+ struct c67x00_lcp_int_data *data)
+{
+ int i, rc;
+
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_write_word(dev, COMM_INT_NUM, nr);
+ for (i = 0; i < COMM_REGS; i++)
+ hpi_write_word(dev, COMM_R(i), data->regs[i]);
+ hpi_send_mbox(dev, COMM_EXEC_INT);
+ rc = ll_recv_msg(dev);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Host specific functions */
+
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
+{
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_write_word(dev, HUSB_pEOT, value);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+}
+
+static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
+{
+ struct c67x00_device *dev = sie->dev;
+ struct c67x00_lcp_int_data data;
+ int rc;
+
+ rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
+ BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
+{
+ struct c67x00_device *dev = sie->dev;
+ struct c67x00_lcp_int_data data;
+ int rc;
+
+ data.regs[0] = 50; /* Reset USB port for 50ms */
+ data.regs[1] = port | (sie->sie_num << 1);
+ rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
+ BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
+{
+ hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
+}
+
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
+}
+
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
+}
+
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
+{
+ /* Set port into host mode */
+ hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
+ c67x00_ll_husb_sie_init(sie);
+ /* Clear interrupts */
+ c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
+ /* Check */
+ if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
+ dev_warn(sie_dev(sie),
+ "SIE %d not set to host mode\n", sie->sie_num);
+}
+
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
+{
+ /* Clear connect change */
+ c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
+
+ /* Enable interrupts */
+ hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_CPU_EN(sie->sie_num));
+ hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
+ SOF_EOP_IRQ_EN | DONE_IRQ_EN);
+
+ /* Enable pull down transistors */
+ hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
+{
+ if ((int_status & MBX_OUT_FLG) == 0)
+ return;
+
+ dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
+ complete(&dev->hpi.lcp.msg_received);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_ll_reset(struct c67x00_device *dev)
+{
+ int rc;
+
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_send_mbox(dev, COMM_RESET);
+ rc = ll_recv_msg(dev);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_ll_write_mem_le16 - write into c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
+{
+ u8 *buf = data;
+
+ /* Sanity check */
+ if (addr + len > 0xffff) {
+ dev_err(&dev->pdev->dev,
+ "Trying to write beyond writable region!\n");
+ return;
+ }
+
+ if (addr & 0x01) {
+ /* unaligned access */
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr - 1);
+ tmp = (tmp & 0x00ff) | (*buf++ << 8);
+ hpi_write_word(dev, addr - 1, tmp);
+ addr++;
+ len--;
+ }
+
+ hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
+ addr += len & ~0x01;
+ len &= 0x01;
+
+ if (len) {
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr);
+ tmp = (tmp & 0xff00) | *buf;
+ hpi_write_word(dev, addr, tmp);
+ }
+}
+
+/**
+ * c67x00_ll_read_mem_le16 - read from c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
+{
+ u8 *buf = data;
+
+ if (addr & 0x01) {
+ /* unaligned access */
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr - 1);
+ *buf++ = (tmp >> 8) & 0x00ff;
+ addr++;
+ len--;
+ }
+
+ hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
+ addr += len & ~0x01;
+ len &= 0x01;
+
+ if (len) {
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr);
+ *buf = tmp & 0x00ff;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_init(struct c67x00_device *dev)
+{
+ mutex_init(&dev->hpi.lcp.mutex);
+ init_completion(&dev->hpi.lcp.msg_received);
+}
+
+void c67x00_ll_release(struct c67x00_device *dev)
+{
+}
diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c
new file mode 100644
index 000000000000..85dfe2965661
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-sched.c
@@ -0,0 +1,1170 @@
+/*
+ * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/kthread.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/*
+ * These are the stages for a control urb, they are kept
+ * in both urb->interval and td->privdata.
+ */
+#define SETUP_STAGE 0
+#define DATA_STAGE 1
+#define STATUS_STAGE 2
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct c67x00_ep_data: Host endpoint data structure
+ */
+struct c67x00_ep_data {
+ struct list_head queue;
+ struct list_head node;
+ struct usb_host_endpoint *hep;
+ struct usb_device *dev;
+ u16 next_frame; /* For int/isoc transactions */
+};
+
+/**
+ * struct c67x00_td
+ *
+ * Hardware parts are little endiannes, SW in CPU endianess.
+ */
+struct c67x00_td {
+ /* HW specific part */
+ __le16 ly_base_addr; /* Bytes 0-1 */
+ __le16 port_length; /* Bytes 2-3 */
+ u8 pid_ep; /* Byte 4 */
+ u8 dev_addr; /* Byte 5 */
+ u8 ctrl_reg; /* Byte 6 */
+ u8 status; /* Byte 7 */
+ u8 retry_cnt; /* Byte 8 */
+#define TT_OFFSET 2
+#define TT_CONTROL 0
+#define TT_ISOCHRONOUS 1
+#define TT_BULK 2
+#define TT_INTERRUPT 3
+ u8 residue; /* Byte 9 */
+ __le16 next_td_addr; /* Bytes 10-11 */
+ /* SW part */
+ struct list_head td_list;
+ u16 td_addr;
+ void *data;
+ struct urb *urb;
+ unsigned long privdata;
+
+ /* These are needed for handling the toggle bits:
+ * an urb can be dequeued while a td is in progress
+ * after checking the td, the toggle bit might need to
+ * be fixed */
+ struct c67x00_ep_data *ep_data;
+ unsigned int pipe;
+};
+
+struct c67x00_urb_priv {
+ struct list_head hep_node;
+ struct urb *urb;
+ int port;
+ int cnt; /* packet number for isoc */
+ int status;
+ struct c67x00_ep_data *ep_data;
+};
+
+#define td_udev(td) ((td)->ep_data->dev)
+
+#define CY_TD_SIZE 12
+
+#define TD_PIDEP_OFFSET 0x04
+#define TD_PIDEPMASK_PID 0xF0
+#define TD_PIDEPMASK_EP 0x0F
+#define TD_PORTLENMASK_DL 0x02FF
+#define TD_PORTLENMASK_PN 0xC000
+
+#define TD_STATUS_OFFSET 0x07
+#define TD_STATUSMASK_ACK 0x01
+#define TD_STATUSMASK_ERR 0x02
+#define TD_STATUSMASK_TMOUT 0x04
+#define TD_STATUSMASK_SEQ 0x08
+#define TD_STATUSMASK_SETUP 0x10
+#define TD_STATUSMASK_OVF 0x20
+#define TD_STATUSMASK_NAK 0x40
+#define TD_STATUSMASK_STALL 0x80
+
+#define TD_ERROR_MASK (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \
+ TD_STATUSMASK_STALL)
+
+#define TD_RETRYCNT_OFFSET 0x08
+#define TD_RETRYCNTMASK_ACT_FLG 0x10
+#define TD_RETRYCNTMASK_TX_TYPE 0x0C
+#define TD_RETRYCNTMASK_RTY_CNT 0x03
+
+#define TD_RESIDUE_OVERFLOW 0x80
+
+#define TD_PID_IN 0x90
+
+/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */
+#define td_residue(td) ((__s8)(td->residue))
+#define td_ly_base_addr(td) (__le16_to_cpu((td)->ly_base_addr))
+#define td_port_length(td) (__le16_to_cpu((td)->port_length))
+#define td_next_td_addr(td) (__le16_to_cpu((td)->next_td_addr))
+
+#define td_active(td) ((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG)
+#define td_length(td) (td_port_length(td) & TD_PORTLENMASK_DL)
+
+#define td_sequence_ok(td) (!td->status || \
+ (!(td->status & TD_STATUSMASK_SEQ) == \
+ !(td->ctrl_reg & SEQ_SEL)))
+
+#define td_acked(td) (!td->status || \
+ (td->status & TD_STATUSMASK_ACK))
+#define td_actual_bytes(td) (td_length(td) - td_residue(td))
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef DEBUG
+
+/**
+ * dbg_td - Dump the contents of the TD
+ */
+static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
+{
+ struct device *dev = c67x00_hcd_dev(c67x00);
+
+ dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr);
+ dev_dbg(dev, "urb: 0x%p\n", td->urb);
+ dev_dbg(dev, "endpoint: %4d\n", usb_pipeendpoint(td->pipe));
+ dev_dbg(dev, "pipeout: %4d\n", usb_pipeout(td->pipe));
+ dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td));
+ dev_dbg(dev, "port_length: 0x%04x\n", td_port_length(td));
+ dev_dbg(dev, "pid_ep: 0x%02x\n", td->pid_ep);
+ dev_dbg(dev, "dev_addr: 0x%02x\n", td->dev_addr);
+ dev_dbg(dev, "ctrl_reg: 0x%02x\n", td->ctrl_reg);
+ dev_dbg(dev, "status: 0x%02x\n", td->status);
+ dev_dbg(dev, "retry_cnt: 0x%02x\n", td->retry_cnt);
+ dev_dbg(dev, "residue: 0x%02x\n", td->residue);
+ dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td));
+ dev_dbg(dev, "data:");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
+ td->data, td_length(td), 1);
+}
+#else /* DEBUG */
+
+static inline void
+dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { }
+
+#endif /* DEBUG */
+
+/* -------------------------------------------------------------------------- */
+/* Helper functions */
+
+static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00)
+{
+ return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_add
+ * Software wraparound for framenumbers.
+ */
+static inline u16 frame_add(u16 a, u16 b)
+{
+ return (a + b) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_after - is frame a after frame b
+ */
+static inline int frame_after(u16 a, u16 b)
+{
+ return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) <
+ (HOST_FRAME_MASK / 2);
+}
+
+/**
+ * frame_after_eq - is frame a after or equal to frame b
+ */
+static inline int frame_after_eq(u16 a, u16 b)
+{
+ return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) <
+ (HOST_FRAME_MASK / 2);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_release_urb - remove link from all tds to this urb
+ * Disconnects the urb from it's tds, so that it can be given back.
+ * pre: urb->hcpriv != NULL
+ */
+static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_td *td;
+ struct c67x00_urb_priv *urbp;
+
+ BUG_ON(!urb);
+
+ c67x00->urb_count--;
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ c67x00->urb_iso_count--;
+ if (c67x00->urb_iso_count == 0)
+ c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+ }
+
+ /* TODO this might be not so efficient when we've got many urbs!
+ * Alternatives:
+ * * only clear when needed
+ * * keep a list of tds with each urbp
+ */
+ list_for_each_entry(td, &c67x00->td_list, td_list)
+ if (urb == td->urb)
+ td->urb = NULL;
+
+ urbp = urb->hcpriv;
+ urb->hcpriv = NULL;
+ list_del(&urbp->hep_node);
+ kfree(urbp);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct c67x00_ep_data *
+c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct usb_host_endpoint *hep = urb->ep;
+ struct c67x00_ep_data *ep_data;
+ int type;
+
+ c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+
+ /* Check if endpoint already has a c67x00_ep_data struct allocated */
+ if (hep->hcpriv) {
+ ep_data = hep->hcpriv;
+ if (frame_after(c67x00->current_frame, ep_data->next_frame))
+ ep_data->next_frame =
+ frame_add(c67x00->current_frame, 1);
+ return hep->hcpriv;
+ }
+
+ /* Allocate and initialize a new c67x00 endpoint data structure */
+ ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC);
+ if (!ep_data)
+ return NULL;
+
+ INIT_LIST_HEAD(&ep_data->queue);
+ INIT_LIST_HEAD(&ep_data->node);
+ ep_data->hep = hep;
+
+ /* hold a reference to udev as long as this endpoint lives,
+ * this is needed to possibly fix the data toggle */
+ ep_data->dev = usb_get_dev(urb->dev);
+ hep->hcpriv = ep_data;
+
+ /* For ISOC and INT endpoints, start ASAP: */
+ ep_data->next_frame = frame_add(c67x00->current_frame, 1);
+
+ /* Add the endpoint data to one of the pipe lists; must be added
+ in order of endpoint address */
+ type = usb_pipetype(urb->pipe);
+ if (list_empty(&ep_data->node)) {
+ list_add(&ep_data->node, &c67x00->list[type]);
+ } else {
+ struct c67x00_ep_data *prev;
+
+ list_for_each_entry(prev, &c67x00->list[type], node) {
+ if (prev->hep->desc.bEndpointAddress >
+ hep->desc.bEndpointAddress) {
+ list_add(&ep_data->node, prev->node.prev);
+ break;
+ }
+ }
+ }
+
+ return ep_data;
+}
+
+static int c67x00_ep_data_free(struct usb_host_endpoint *hep)
+{
+ struct c67x00_ep_data *ep_data = hep->hcpriv;
+
+ if (!ep_data)
+ return 0;
+
+ if (!list_empty(&ep_data->queue))
+ return -EBUSY;
+
+ usb_put_dev(ep_data->dev);
+ list_del(&ep_data->queue);
+ list_del(&ep_data->node);
+
+ kfree(ep_data);
+ hep->hcpriv = NULL;
+
+ return 0;
+}
+
+void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ unsigned long flags;
+
+ if (!list_empty(&ep->urb_list))
+ dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+
+ /* loop waiting for all transfers in the endpoint queue to complete */
+ while (c67x00_ep_data_free(ep)) {
+ /* Drop the lock so we can sleep waiting for the hardware */
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ /* it could happen that we reinitialize this completion, while
+ * somebody was waiting for that completion. The timeout and
+ * while loop handle such cases, but this might be improved */
+ INIT_COMPLETION(c67x00->endpoint_disable);
+ c67x00_sched_kick(c67x00);
+ wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ);
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ }
+
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int get_root_port(struct usb_device *dev)
+{
+ while (dev->parent->parent)
+ dev = dev->parent;
+ return dev->portnum;
+}
+
+int c67x00_urb_enqueue(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags)
+{
+ int ret;
+ unsigned long flags;
+ struct c67x00_urb_priv *urbp;
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ int port = get_root_port(urb->dev)-1;
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+
+ /* Make sure host controller is running */
+ if (!HC_IS_RUNNING(hcd->state)) {
+ ret = -ENODEV;
+ goto err_not_linked;
+ }
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto err_not_linked;
+
+ /* Allocate and initialize urb private data */
+ urbp = kzalloc(sizeof(*urbp), mem_flags);
+ if (!urbp) {
+ ret = -ENOMEM;
+ goto err_urbp;
+ }
+
+ INIT_LIST_HEAD(&urbp->hep_node);
+ urbp->urb = urb;
+ urbp->port = port;
+
+ urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb);
+
+ if (!urbp->ep_data) {
+ ret = -ENOMEM;
+ goto err_epdata;
+ }
+
+ /* TODO claim bandwidth with usb_claim_bandwidth?
+ * also release it somewhere! */
+
+ urb->hcpriv = urbp;
+
+ urb->actual_length = 0; /* Nothing received/transmitted yet */
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ urb->interval = SETUP_STAGE;
+ break;
+ case PIPE_INTERRUPT:
+ break;
+ case PIPE_BULK:
+ break;
+ case PIPE_ISOCHRONOUS:
+ if (c67x00->urb_iso_count == 0)
+ c67x00->max_frame_bw = MAX_FRAME_BW_ISO;
+ c67x00->urb_iso_count++;
+ /* Assume always URB_ISO_ASAP, FIXME */
+ if (list_empty(&urbp->ep_data->queue))
+ urb->start_frame = urbp->ep_data->next_frame;
+ else {
+ /* Go right after the last one */
+ struct urb *last_urb;
+
+ last_urb = list_entry(urbp->ep_data->queue.prev,
+ struct c67x00_urb_priv,
+ hep_node)->urb;
+ urb->start_frame =
+ frame_add(last_urb->start_frame,
+ last_urb->number_of_packets *
+ last_urb->interval);
+ }
+ urbp->cnt = 0;
+ break;
+ }
+
+ /* Add the URB to the endpoint queue */
+ list_add_tail(&urbp->hep_node, &urbp->ep_data->queue);
+
+ /* If this is the only URB, kick start the controller */
+ if (!c67x00->urb_count++)
+ c67x00_ll_hpi_enable_sofeop(c67x00->sie);
+
+ c67x00_sched_kick(c67x00);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return 0;
+
+err_epdata:
+ kfree(urbp);
+err_urbp:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+err_not_linked:
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return ret;
+}
+
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
+ c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&c67x00->lock);
+
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return 0;
+
+ done:
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * pre: c67x00 locked, urb unlocked
+ */
+static void
+c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
+{
+ struct c67x00_urb_priv *urbp;
+
+ if (!urb)
+ return;
+
+ urbp = urb->hcpriv;
+ urbp->status = status;
+
+ list_del_init(&urbp->hep_node);
+
+ c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb);
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status);
+ spin_lock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
+ int len, int periodic)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+ int bit_time;
+
+ /* According to the C67x00 BIOS user manual, page 3-18,19, the
+ * following calculations provide the full speed bit times for
+ * a transaction.
+ *
+ * FS(in) = 112.5 + 9.36*BC + HOST_DELAY
+ * FS(in,iso) = 90.5 + 9.36*BC + HOST_DELAY
+ * FS(out) = 112.5 + 9.36*BC + HOST_DELAY
+ * FS(out,iso) = 78.4 + 9.36*BC + HOST_DELAY
+ * LS(in) = 802.4 + 75.78*BC + HOST_DELAY
+ * LS(out) = 802.6 + 74.67*BC + HOST_DELAY
+ *
+ * HOST_DELAY == 106 for the c67200 and c67300.
+ */
+
+ /* make calculations in 1/100 bit times to maintain resolution */
+ if (urbp->ep_data->dev->speed == USB_SPEED_LOW) {
+ /* Low speed pipe */
+ if (usb_pipein(urb->pipe))
+ bit_time = 80240 + 7578*len;
+ else
+ bit_time = 80260 + 7467*len;
+ } else {
+ /* FS pipes */
+ if (usb_pipeisoc(urb->pipe))
+ bit_time = usb_pipein(urb->pipe) ? 9050 : 7840;
+ else
+ bit_time = 11250;
+ bit_time += 936*len;
+ }
+
+ /* Scale back down to integer bit times. Use a host delay of 106.
+ * (this is the only place it is used) */
+ bit_time = ((bit_time+50) / 100) + 106;
+
+ if (unlikely(bit_time + c67x00->bandwidth_allocated >=
+ c67x00->max_frame_bw))
+ return -EMSGSIZE;
+
+ if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >=
+ c67x00->td_base_addr + SIE_TD_SIZE))
+ return -EMSGSIZE;
+
+ if (unlikely(c67x00->next_buf_addr + len >=
+ c67x00->buf_base_addr + SIE_TD_BUF_SIZE))
+ return -EMSGSIZE;
+
+ if (periodic) {
+ if (unlikely(bit_time + c67x00->periodic_bw_allocated >=
+ MAX_PERIODIC_BW(c67x00->max_frame_bw)))
+ return -EMSGSIZE;
+ c67x00->periodic_bw_allocated += bit_time;
+ }
+
+ c67x00->bandwidth_allocated += bit_time;
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * td_addr and buf_addr must be word aligned
+ */
+static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
+ void *data, int len, int pid, int toggle,
+ unsigned long privdata)
+{
+ struct c67x00_td *td;
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+ const __u8 active_flag = 1, retry_cnt = 1;
+ __u8 cmd = 0;
+ int tt = 0;
+
+ if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
+ || usb_pipeint(urb->pipe)))
+ return -EMSGSIZE; /* Not really an error, but expected */
+
+ td = kzalloc(sizeof(*td), GFP_ATOMIC);
+ if (!td)
+ return -ENOMEM;
+
+ td->pipe = urb->pipe;
+ td->ep_data = urbp->ep_data;
+
+ if ((td_udev(td)->speed == USB_SPEED_LOW) &&
+ !(c67x00->low_speed_ports & (1 << urbp->port)))
+ cmd |= PREAMBLE_EN;
+
+ switch (usb_pipetype(td->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ tt = TT_ISOCHRONOUS;
+ cmd |= ISO_EN;
+ break;
+ case PIPE_CONTROL:
+ tt = TT_CONTROL;
+ break;
+ case PIPE_BULK:
+ tt = TT_BULK;
+ break;
+ case PIPE_INTERRUPT:
+ tt = TT_INTERRUPT;
+ break;
+ }
+
+ if (toggle)
+ cmd |= SEQ_SEL;
+
+ cmd |= ARM_EN;
+
+ /* SW part */
+ td->td_addr = c67x00->next_td_addr;
+ c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE;
+
+ /* HW part */
+ td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr);
+ td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) |
+ (urbp->port << 14) | (len & 0x3FF));
+ td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) |
+ (usb_pipeendpoint(td->pipe) & 0xF);
+ td->dev_addr = usb_pipedevice(td->pipe) & 0x7F;
+ td->ctrl_reg = cmd;
+ td->status = 0;
+ td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt;
+ td->residue = 0;
+ td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr);
+
+ /* SW part */
+ td->data = data;
+ td->urb = urb;
+ td->privdata = privdata;
+
+ c67x00->next_buf_addr += (len + 1) & ~0x01; /* properly align */
+
+ list_add_tail(&td->td_list, &c67x00->td_list);
+ return 0;
+}
+
+static inline void c67x00_release_td(struct c67x00_td *td)
+{
+ list_del_init(&td->td_list);
+ kfree(td);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ int remaining;
+ int toggle;
+ int pid;
+ int ret = 0;
+ int maxps;
+ int need_empty;
+
+ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ remaining = urb->transfer_buffer_length - urb->actual_length;
+
+ maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+ usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+ while (remaining || need_empty) {
+ int len;
+ char *td_buf;
+
+ len = (remaining > maxps) ? maxps : remaining;
+ if (!len)
+ need_empty = 0;
+
+ pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+ td_buf = urb->transfer_buffer + urb->transfer_buffer_length -
+ remaining;
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle,
+ DATA_STAGE);
+ if (ret)
+ return ret; /* td wasn't created */
+
+ toggle ^= 1;
+ remaining -= len;
+ if (usb_pipecontrol(urb->pipe))
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ int ret;
+ int pid;
+
+ switch (urb->interval) {
+ default:
+ case SETUP_STAGE:
+ ret = c67x00_create_td(c67x00, urb, urb->setup_packet,
+ 8, USB_PID_SETUP, 0, SETUP_STAGE);
+ if (ret)
+ return ret;
+ urb->interval = SETUP_STAGE;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), 1);
+ break;
+ case DATA_STAGE:
+ if (urb->transfer_buffer_length) {
+ ret = c67x00_add_data_urb(c67x00, urb);
+ if (ret)
+ return ret;
+ break;
+ } /* else fallthrough */
+ case STATUS_STAGE:
+ pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+ ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
+ STATUS_STAGE);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+ if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+ urbp->ep_data->next_frame =
+ frame_add(urbp->ep_data->next_frame, urb->interval);
+ return c67x00_add_data_urb(c67x00, urb);
+ }
+ return 0;
+}
+
+static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+ if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+ char *td_buf;
+ int len, pid, ret;
+
+ BUG_ON(urbp->cnt >= urb->number_of_packets);
+
+ td_buf = urb->transfer_buffer +
+ urb->iso_frame_desc[urbp->cnt].offset;
+ len = urb->iso_frame_desc[urbp->cnt].length;
+ pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,
+ urbp->cnt);
+ if (ret) {
+ printk(KERN_DEBUG "create failed: %d\n", ret);
+ urb->iso_frame_desc[urbp->cnt].actual_length = 0;
+ urb->iso_frame_desc[urbp->cnt].status = ret;
+ if (urbp->cnt + 1 == urb->number_of_packets)
+ c67x00_giveback_urb(c67x00, urb, 0);
+ }
+
+ urbp->ep_data->next_frame =
+ frame_add(urbp->ep_data->next_frame, urb->interval);
+ urbp->cnt++;
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type,
+ int (*add)(struct c67x00_hcd *, struct urb *))
+{
+ struct c67x00_ep_data *ep_data;
+ struct urb *urb;
+
+ /* traverse every endpoint on the list */
+ list_for_each_entry(ep_data, &c67x00->list[type], node) {
+ if (!list_empty(&ep_data->queue)) {
+ /* and add the first urb */
+ /* isochronous transfer rely on this */
+ urb = list_entry(ep_data->queue.next,
+ struct c67x00_urb_priv,
+ hep_node)->urb;
+ add(c67x00, urb);
+ }
+ }
+}
+
+static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td, *ttd;
+
+ /* Check if we can proceed */
+ if (!list_empty(&c67x00->td_list)) {
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "TD list not empty! This should not happen!\n");
+ list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
+ dbg_td(c67x00, td, "Unprocessed td");
+ c67x00_release_td(td);
+ }
+ }
+
+ /* Reinitialize variables */
+ c67x00->bandwidth_allocated = 0;
+ c67x00->periodic_bw_allocated = 0;
+
+ c67x00->next_td_addr = c67x00->td_base_addr;
+ c67x00->next_buf_addr = c67x00->buf_base_addr;
+
+ /* Fill the list */
+ c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb);
+ c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb);
+ c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb);
+ c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Get TD from C67X00
+ */
+static inline void
+c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ c67x00_ll_read_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
+
+ if (usb_pipein(td->pipe) && td_actual_bytes(td))
+ c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, td_actual_bytes(td));
+}
+
+static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ if (td->status & TD_STATUSMASK_ERR) {
+ dbg_td(c67x00, td, "ERROR_FLAG");
+ return -EILSEQ;
+ }
+ if (td->status & TD_STATUSMASK_STALL) {
+ /* dbg_td(c67x00, td, "STALL"); */
+ return -EPIPE;
+ }
+ if (td->status & TD_STATUSMASK_TMOUT) {
+ dbg_td(c67x00, td, "TIMEOUT");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline int c67x00_end_of_data(struct c67x00_td *td)
+{
+ int maxps, need_empty, remaining;
+ struct urb *urb = td->urb;
+ int act_bytes;
+
+ act_bytes = td_actual_bytes(td);
+
+ if (unlikely(!act_bytes))
+ return 1; /* This was an empty packet */
+
+ maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe));
+
+ if (unlikely(act_bytes < maxps))
+ return 1; /* Smaller then full packet */
+
+ remaining = urb->transfer_buffer_length - urb->actual_length;
+ need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+ usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+ if (unlikely(!remaining && !need_empty))
+ return 1;
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Remove all td's from the list which come
+ * after last_td and are meant for the same pipe.
+ * This is used when a short packet has occured */
+static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00,
+ struct c67x00_td *last_td)
+{
+ struct c67x00_td *td, *tmp;
+ td = last_td;
+ tmp = last_td;
+ while (td->td_list.next != &c67x00->td_list) {
+ td = list_entry(td->td_list.next, struct c67x00_td, td_list);
+ if (td->pipe == last_td->pipe) {
+ c67x00_release_td(td);
+ td = tmp;
+ }
+ tmp = td;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
+ struct c67x00_td *td)
+{
+ struct urb *urb = td->urb;
+
+ if (!urb)
+ return;
+
+ urb->actual_length += td_actual_bytes(td);
+
+ switch (usb_pipetype(td->pipe)) {
+ /* isochronous tds are handled separately */
+ case PIPE_CONTROL:
+ switch (td->privdata) {
+ case SETUP_STAGE:
+ urb->interval =
+ urb->transfer_buffer_length ?
+ DATA_STAGE : STATUS_STAGE;
+ /* Don't count setup_packet with normal data: */
+ urb->actual_length = 0;
+ break;
+
+ case DATA_STAGE:
+ if (c67x00_end_of_data(td)) {
+ urb->interval = STATUS_STAGE;
+ c67x00_clear_pipe(c67x00, td);
+ }
+ break;
+
+ case STATUS_STAGE:
+ urb->interval = 0;
+ c67x00_giveback_urb(c67x00, urb, 0);
+ break;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ case PIPE_BULK:
+ if (unlikely(c67x00_end_of_data(td))) {
+ c67x00_clear_pipe(c67x00, td);
+ c67x00_giveback_urb(c67x00, urb, 0);
+ }
+ break;
+ }
+}
+
+static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ struct urb *urb = td->urb;
+ struct c67x00_urb_priv *urbp;
+ int cnt;
+
+ if (!urb)
+ return;
+
+ urbp = urb->hcpriv;
+ cnt = td->privdata;
+
+ if (td->status & TD_ERROR_MASK)
+ urb->error_count++;
+
+ urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td);
+ urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td);
+ if (cnt + 1 == urb->number_of_packets) /* Last packet */
+ c67x00_giveback_urb(c67x00, urb, 0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_check_td_list - handle tds which have been processed by the c67x00
+ * pre: current_td == 0
+ */
+static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td, *tmp;
+ struct urb *urb;
+ int ack_ok;
+ int clear_endpoint;
+
+ list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) {
+ /* get the TD */
+ c67x00_parse_td(c67x00, td);
+ urb = td->urb; /* urb can be NULL! */
+ ack_ok = 0;
+ clear_endpoint = 1;
+
+ /* Handle isochronous transfers separately */
+ if (usb_pipeisoc(td->pipe)) {
+ clear_endpoint = 0;
+ c67x00_handle_isoc(c67x00, td);
+ goto cont;
+ }
+
+ /* When an error occurs, all td's for that pipe go into an
+ * inactive state. This state matches successful transfers so
+ * we must make sure not to service them. */
+ if (td->status & TD_ERROR_MASK) {
+ c67x00_giveback_urb(c67x00, urb,
+ c67x00_td_to_error(c67x00, td));
+ goto cont;
+ }
+
+ if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) ||
+ !td_acked(td))
+ goto cont;
+
+ /* Sequence ok and acked, don't need to fix toggle */
+ ack_ok = 1;
+
+ if (unlikely(td->status & TD_STATUSMASK_OVF)) {
+ if (td_residue(td) & TD_RESIDUE_OVERFLOW) {
+ /* Overflow */
+ c67x00_giveback_urb(c67x00, urb, -EOVERFLOW);
+ goto cont;
+ }
+ }
+
+ clear_endpoint = 0;
+ c67x00_handle_successful_td(c67x00, td);
+
+cont:
+ if (clear_endpoint)
+ c67x00_clear_pipe(c67x00, td);
+ if (ack_ok)
+ usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe),
+ usb_pipeout(td->pipe),
+ !(td->ctrl_reg & SEQ_SEL));
+ /* next in list could have been removed, due to clear_pipe! */
+ tmp = list_entry(td->td_list.next, typeof(*td), td_list);
+ c67x00_release_td(td);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00)
+{
+ /* If all tds are processed, we can check the previous frame (if
+ * there was any) and start our next frame.
+ */
+ return !c67x00_ll_husb_get_current_td(c67x00->sie);
+}
+
+/**
+ * Send td to C67X00
+ */
+static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ int len = td_length(td);
+
+ if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN))
+ c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, len);
+
+ c67x00_ll_write_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
+}
+
+static void c67x00_send_frame(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td;
+
+ if (list_empty(&c67x00->td_list))
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "%s: td list should not be empty here!\n",
+ __func__);
+
+ list_for_each_entry(td, &c67x00->td_list, td_list) {
+ if (td->td_list.next == &c67x00->td_list)
+ td->next_td_addr = 0; /* Last td in list */
+
+ c67x00_send_td(c67x00, td);
+ }
+
+ c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_do_work - Schedulers state machine
+ */
+static void c67x00_do_work(struct c67x00_hcd *c67x00)
+{
+ spin_lock(&c67x00->lock);
+ /* Make sure all tds are processed */
+ if (!c67x00_all_tds_processed(c67x00))
+ goto out;
+
+ c67x00_check_td_list(c67x00);
+
+ /* no td's are being processed (current == 0)
+ * and all have been "checked" */
+ complete(&c67x00->endpoint_disable);
+
+ if (!list_empty(&c67x00->td_list))
+ goto out;
+
+ c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+ if (c67x00->current_frame == c67x00->last_frame)
+ goto out; /* Don't send tds in same frame */
+ c67x00->last_frame = c67x00->current_frame;
+
+ /* If no urbs are scheduled, our work is done */
+ if (!c67x00->urb_count) {
+ c67x00_ll_hpi_disable_sofeop(c67x00->sie);
+ goto out;
+ }
+
+ c67x00_fill_frame(c67x00);
+ if (!list_empty(&c67x00->td_list))
+ /* TD's have been added to the frame */
+ c67x00_send_frame(c67x00);
+
+ out:
+ spin_unlock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_sched_tasklet(unsigned long __c67x00)
+{
+ struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00;
+ c67x00_do_work(c67x00);
+}
+
+void c67x00_sched_kick(struct c67x00_hcd *c67x00)
+{
+ tasklet_hi_schedule(&c67x00->tasklet);
+}
+
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00)
+{
+ tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet,
+ (unsigned long)c67x00);
+ return 0;
+}
+
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00)
+{
+ tasklet_kill(&c67x00->tasklet);
+}
diff --git a/drivers/usb/c67x00/c67x00.h b/drivers/usb/c67x00/c67x00.h
new file mode 100644
index 000000000000..a26e9ded0f32
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00.h
@@ -0,0 +1,294 @@
+/*
+ * c67x00.h: Cypress C67X00 USB register and field definitions
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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.
+ */
+
+#ifndef _USB_C67X00_H
+#define _USB_C67X00_H
+
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+/* ---------------------------------------------------------------------
+ * Cypress C67x00 register definitions
+ */
+
+/* Hardware Revision Register */
+#define HW_REV_REG 0xC004
+
+/* General USB registers */
+/* ===================== */
+
+/* USB Control Register */
+#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A)
+
+#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400)
+#define HOST_MODE 0x0200
+#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080)
+#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001)
+
+/* USB status register - Notice it has different content in hcd/udc mode */
+#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090)
+
+#define EP0_IRQ_FLG 0x0001
+#define EP1_IRQ_FLG 0x0002
+#define EP2_IRQ_FLG 0x0004
+#define EP3_IRQ_FLG 0x0008
+#define EP4_IRQ_FLG 0x0010
+#define EP5_IRQ_FLG 0x0020
+#define EP6_IRQ_FLG 0x0040
+#define EP7_IRQ_FLG 0x0080
+#define RESET_IRQ_FLG 0x0100
+#define SOF_EOP_IRQ_FLG 0x0200
+#define ID_IRQ_FLG 0x4000
+#define VBUS_IRQ_FLG 0x8000
+
+/* USB Host only registers */
+/* ======================= */
+
+/* Host n Control Register */
+#define HOST_CTL_REG(x) ((x) ? 0xC0A0 : 0xC080)
+
+#define PREAMBLE_EN 0x0080 /* Preamble enable */
+#define SEQ_SEL 0x0040 /* Data Toggle Sequence Bit Select */
+#define ISO_EN 0x0010 /* Isochronous enable */
+#define ARM_EN 0x0001 /* Arm operation */
+
+/* Host n Interrupt Enable Register */
+#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */
+#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */
+#define ID_IRQ_EN 0x4000 /* ID interrupt enable */
+#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */
+#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */
+
+/* USB status register */
+#define HOST_STAT_MASK 0x02FD
+#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010)
+#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004)
+
+/* Host Frame Register */
+#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096)
+
+#define HOST_FRAME_MASK 0x07FF
+
+/* USB Peripheral only registers */
+/* ============================= */
+
+/* Device n Port Sel reg */
+#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084)
+
+/* Device n Interrupt Enable Register */
+#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \
+ ? (0x0280 + (ep << 4)) \
+ : (0x0200 + (ep << 4)))
+#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \
+ ? (0x0286 + (ep << 4)) \
+ : (0x0206 + (ep << 4)))
+
+#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E))
+
+/* HPI registers */
+/* ============= */
+
+/* HPI Status register */
+#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10))
+#define SIEMSG_FLG(x) (1 << (4 + (x)))
+#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_FLG(x) (1 << (2 + (x)))
+#define RESUME_FLG(x) (1 << (6 + (x)))
+#define MBX_OUT_FLG 0x0001 /* Message out available */
+#define MBX_IN_FLG 0x0100
+#define ID_FLG 0x4000
+#define VBUS_FLG 0x8000
+
+/* Interrupt routing register */
+#define HPI_IRQ_ROUTING_REG 0x0142
+
+#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001)
+#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004)
+#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040)
+#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800)
+#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400)
+#define ID_TO_HPI_ENABLE 0x4000
+#define VBUS_TO_HPI_ENABLE 0x8000
+
+/* SIE msg registers */
+#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144)
+
+#define HUSB_TDListDone 0x1000
+
+#define SUSB_EP0_MSG 0x0001
+#define SUSB_EP1_MSG 0x0002
+#define SUSB_EP2_MSG 0x0004
+#define SUSB_EP3_MSG 0x0008
+#define SUSB_EP4_MSG 0x0010
+#define SUSB_EP5_MSG 0x0020
+#define SUSB_EP6_MSG 0x0040
+#define SUSB_EP7_MSG 0x0080
+#define SUSB_RST_MSG 0x0100
+#define SUSB_SOF_MSG 0x0200
+#define SUSB_CFG_MSG 0x0400
+#define SUSB_SUS_MSG 0x0800
+#define SUSB_ID_MSG 0x4000
+#define SUSB_VBUS_MSG 0x8000
+
+/* BIOS interrupt routines */
+
+#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81)
+#define SUSBx_SEND_INT(x) ((x) ? 96 : 80)
+
+#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4)
+#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6)
+#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
+
+#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */
+#define SIE_TD_SIZE 0x200 /* size of the td list */
+#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */
+
+#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
+#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE)
+
+/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
+#define CY_UDC_REQ_HEADER_BASE 0x1100
+/* 8- byte request headers for IN/OUT transfers */
+#define CY_UDC_REQ_HEADER_SIZE 8
+
+#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \
+ ((ep_num) * CY_UDC_REQ_HEADER_SIZE))
+#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8))
+
+#define CY_UDC_BIOS_REPLACE_BASE 0x1800
+#define CY_UDC_REQ_BUFFER_BASE 0x2000
+#define CY_UDC_REQ_BUFFER_SIZE 0x0400
+#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \
+ ((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
+
+/* ---------------------------------------------------------------------
+ * Driver data structures
+ */
+
+struct c67x00_device;
+
+/**
+ * struct c67x00_sie - Common data associated with a SIE
+ * @lock: lock to protect this struct and the associated chip registers
+ * @private_data: subdriver dependent data
+ * @irq: subdriver dependent irq handler, set NULL when not used
+ * @dev: link to common driver structure
+ * @sie_num: SIE number on chip, starting from 0
+ * @mode: SIE mode (host/peripheral/otg/not used)
+ */
+struct c67x00_sie {
+ /* Entries to be used by the subdrivers */
+ spinlock_t lock; /* protect this structure */
+ void *private_data;
+ void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
+
+ /* Read only: */
+ struct c67x00_device *dev;
+ int sie_num;
+ int mode;
+};
+
+#define sie_dev(s) (&(s)->dev->pdev->dev)
+
+/**
+ * struct c67x00_lcp
+ */
+struct c67x00_lcp {
+ /* Internal use only */
+ struct mutex mutex;
+ struct completion msg_received;
+ u16 last_msg;
+};
+
+/*
+ * struct c67x00_hpi
+ */
+struct c67x00_hpi {
+ void __iomem *base;
+ int regstep;
+ spinlock_t lock;
+ struct c67x00_lcp lcp;
+};
+
+#define C67X00_SIES 2
+#define C67X00_PORTS 2
+
+/**
+ * struct c67x00_device - Common data associated with a c67x00 instance
+ * @hpi: hpi addresses
+ * @sie: array of sie's on this chip
+ * @pdev: platform device of instance
+ * @pdata: configuration provided by the platform
+ */
+struct c67x00_device {
+ struct c67x00_hpi hpi;
+ struct c67x00_sie sie[C67X00_SIES];
+ struct platform_device *pdev;
+ struct c67x00_platform_data *pdata;
+};
+
+/* ---------------------------------------------------------------------
+ * Low level interface functions
+ */
+
+/* Host Port Interface (HPI) functions */
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
+
+/* General functions */
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num);
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+
+/* Host specific functions */
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value);
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port);
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr);
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie);
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie);
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
+
+/* Called by c67x00_irq to handle lcp interrupts */
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
+
+/* Setup and teardown */
+void c67x00_ll_init(struct c67x00_device *dev);
+void c67x00_ll_release(struct c67x00_device *dev);
+int c67x00_ll_reset(struct c67x00_device *dev);
+
+#endif /* _USB_C67X00_H */
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 7b572e75e73c..63c34043b4d9 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -280,7 +280,7 @@ static void acm_ctrl_irq(struct urb *urb)
case USB_CDC_NOTIFY_SERIAL_STATE:
- newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
+ newctrl = get_unaligned_le16(data);
if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
dbg("calling hangup");
@@ -1248,6 +1248,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
+ { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
+ .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,
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 99e5a68a3f12..fae55a31e26d 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -156,6 +156,10 @@ static struct attribute *ep_dev_attrs[] = {
static struct attribute_group ep_dev_attr_grp = {
.attrs = ep_dev_attrs,
};
+static struct attribute_group *ep_dev_groups[] = {
+ &ep_dev_attr_grp,
+ NULL
+};
static int usb_endpoint_major_init(void)
{
@@ -298,6 +302,7 @@ int usb_create_ep_files(struct device *parent,
ep_dev->desc = &endpoint->desc;
ep_dev->udev = udev;
+ ep_dev->dev.groups = ep_dev_groups;
ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
ep_dev->dev.class = ep_class->class;
ep_dev->dev.parent = parent;
@@ -309,9 +314,6 @@ int usb_create_ep_files(struct device *parent,
retval = device_register(&ep_dev->dev);
if (retval)
goto error_chrdev;
- retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
- if (retval)
- goto error_group;
/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
@@ -322,8 +324,6 @@ int usb_create_ep_files(struct device *parent,
return retval;
error_link:
- sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
-error_group:
device_unregister(&ep_dev->dev);
destroy_endpoint_class();
return retval;
@@ -348,7 +348,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
- sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
device_unregister(&ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 8607846e3c3f..1d253dd4ea81 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -773,7 +773,7 @@ int __init usbfs_init(void)
usb_register_notify(&usbfs_nb);
/* create mount point for usbfs */
- usbdir = proc_mkdir("usb", proc_bus);
+ usbdir = proc_mkdir("bus/usb", NULL);
return 0;
}
@@ -783,6 +783,6 @@ void usbfs_cleanup(void)
usb_unregister_notify(&usbfs_nb);
unregister_filesystem(&usb_fs_type);
if (usbdir)
- remove_proc_entry("usb", proc_bus);
+ remove_proc_entry("bus/usb", NULL);
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e819e5359d57..fe47d145255a 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -394,7 +394,9 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
if (!io->urbs)
goto nomem;
- urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
+ urb_flags = URB_NO_INTERRUPT;
+ if (dma)
+ urb_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
@@ -1605,6 +1607,7 @@ free_interfaces:
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
+ intf->dev.groups = usb_interface_groups;
intf->dev.dma_mask = dev->dev.dma_mask;
device_initialize(&intf->dev);
mark_quiesced(intf);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 5b20a60de8ba..c783cb111847 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -538,6 +538,46 @@ static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
+/* When modifying this list, be sure to modify dev_string_attrs_are_visible()
+ * accordingly.
+ */
+static struct attribute *dev_string_attrs[] = {
+ &dev_attr_manufacturer.attr,
+ &dev_attr_product.attr,
+ &dev_attr_serial.attr,
+ NULL
+};
+
+static mode_t dev_string_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct usb_device *udev = to_usb_device(
+ container_of(kobj, struct device, kobj));
+
+ if (a == &dev_attr_manufacturer.attr) {
+ if (udev->manufacturer == NULL)
+ return 0;
+ } else if (a == &dev_attr_product.attr) {
+ if (udev->product == NULL)
+ return 0;
+ } else if (a == &dev_attr_serial.attr) {
+ if (udev->serial == NULL)
+ return 0;
+ }
+ return a->mode;
+}
+
+static struct attribute_group dev_string_attr_grp = {
+ .attrs = dev_string_attrs,
+ .is_visible = dev_string_attrs_are_visible,
+};
+
+struct attribute_group *usb_device_groups[] = {
+ &dev_attr_grp,
+ &dev_string_attr_grp,
+ NULL
+};
+
/* Binary descriptors */
static ssize_t
@@ -591,10 +631,9 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
struct device *dev = &udev->dev;
int retval;
- retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
- if (retval)
- return retval;
-
+ /* Unforunately these attributes cannot be created before
+ * the uevent is broadcast.
+ */
retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
if (retval)
goto error;
@@ -607,21 +646,6 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
goto error;
- if (udev->manufacturer) {
- retval = device_create_file(dev, &dev_attr_manufacturer);
- if (retval)
- goto error;
- }
- if (udev->product) {
- retval = device_create_file(dev, &dev_attr_product);
- if (retval)
- goto error;
- }
- if (udev->serial) {
- retval = device_create_file(dev, &dev_attr_serial);
- if (retval)
- goto error;
- }
retval = usb_create_ep_files(dev, &udev->ep0, udev);
if (retval)
goto error;
@@ -636,13 +660,9 @@ 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);
remove_persist_attributes(dev);
device_remove_bin_file(dev, &dev_bin_attr_descriptors);
- sysfs_remove_group(&dev->kobj, &dev_attr_grp);
}
/* Interface Accociation Descriptor fields */
@@ -688,17 +708,15 @@ static ssize_t show_interface_string(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf;
- struct usb_device *udev;
- int len;
+ char *string;
intf = to_usb_interface(dev);
- udev = interface_to_usbdev(intf);
- len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
- if (len < 0)
+ string = intf->cur_altsetting->string;
+ barrier(); /* The altsetting might change! */
+
+ if (!string)
return 0;
- buf[len] = '\n';
- buf[len+1] = 0;
- return len+1;
+ return sprintf(buf, "%s\n", string);
}
static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
@@ -727,18 +745,6 @@ static ssize_t show_modalias(struct device *dev,
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
-static struct attribute *intf_assoc_attrs[] = {
- &dev_attr_iad_bFirstInterface.attr,
- &dev_attr_iad_bInterfaceCount.attr,
- &dev_attr_iad_bFunctionClass.attr,
- &dev_attr_iad_bFunctionSubClass.attr,
- &dev_attr_iad_bFunctionProtocol.attr,
- NULL,
-};
-static struct attribute_group intf_assoc_attr_grp = {
- .attrs = intf_assoc_attrs,
-};
-
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
&dev_attr_bAlternateSetting.attr,
@@ -753,6 +759,37 @@ static struct attribute_group intf_attr_grp = {
.attrs = intf_attrs,
};
+static struct attribute *intf_assoc_attrs[] = {
+ &dev_attr_iad_bFirstInterface.attr,
+ &dev_attr_iad_bInterfaceCount.attr,
+ &dev_attr_iad_bFunctionClass.attr,
+ &dev_attr_iad_bFunctionSubClass.attr,
+ &dev_attr_iad_bFunctionProtocol.attr,
+ NULL,
+};
+
+static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct usb_interface *intf = to_usb_interface(
+ container_of(kobj, struct device, kobj));
+
+ if (intf->intf_assoc == NULL)
+ return 0;
+ return a->mode;
+}
+
+static struct attribute_group intf_assoc_attr_grp = {
+ .attrs = intf_assoc_attrs,
+ .is_visible = intf_assoc_attrs_are_visible,
+};
+
+struct attribute_group *usb_interface_groups[] = {
+ &intf_attr_grp,
+ &intf_assoc_attr_grp,
+ NULL
+};
+
static inline void usb_create_intf_ep_files(struct usb_interface *intf,
struct usb_device *udev)
{
@@ -777,23 +814,21 @@ 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;
if (intf->sysfs_files_created)
return 0;
- retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
- if (retval)
- return retval;
+ /* The interface string may be present in some altsettings
+ * and missing in others. Hence its attribute cannot be created
+ * before the uevent is broadcast.
+ */
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
- retval = device_create_file(dev, &dev_attr_interface);
- if (intf->intf_assoc)
- retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
+ retval = device_create_file(&intf->dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
intf->sysfs_files_created = 1;
return 0;
@@ -807,7 +842,5 @@ void usb_remove_sysfs_intf_files(struct usb_interface *intf)
return;
usb_remove_intf_ep_files(intf);
device_remove_file(dev, &dev_attr_interface);
- sysfs_remove_group(&dev->kobj, &intf_attr_grp);
- sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
intf->sysfs_files_created = 0;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 1f0db51190cc..325774375837 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -291,6 +291,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
+ dev->dev.groups = usb_device_groups;
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 1bf8ccb9c58d..1a8bc21c335e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -130,6 +130,10 @@ static inline int is_active(const struct usb_interface *f)
/* for labeling diagnostics */
extern const char *usbcore_name;
+/* sysfs stuff */
+extern struct attribute_group *usb_device_groups[];
+extern struct attribute_group *usb_interface_groups[];
+
/* usbfs stuff */
extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f7b54651dd42..6e784d2db423 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -231,6 +231,26 @@ config SUPERH_BUILT_IN_M66592
However, this problem is improved if change a value of
NET_IP_ALIGN to 4.
+config USB_GADGET_PXA27X
+ boolean "PXA 27x"
+ depends on ARCH_PXA && PXA27x
+ help
+ Intel's PXA 27x series XScale ARM v5TE processors include
+ an integrated full speed USB 1.1 device controller.
+
+ It has up to 23 endpoints, as well as endpoint zero (for
+ control transfers).
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "pxa27x_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_PXA27X
+ tristate
+ depends on USB_GADGET_PXA27X
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c3aab80b6c76..12357255d740 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
+obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index ce337cb5d137..f261d2a9a5f0 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -3251,7 +3251,7 @@ static int udc_pci_probe(
/* pci setup */
if (pci_enable_device(pdev) < 0) {
kfree(dev);
- dev = 0;
+ dev = NULL;
retval = -ENODEV;
goto finished;
}
@@ -3264,7 +3264,7 @@ static int udc_pci_probe(
if (!request_mem_region(resource, len, name)) {
dev_dbg(&pdev->dev, "pci device used already\n");
kfree(dev);
- dev = 0;
+ dev = NULL;
retval = -EBUSY;
goto finished;
}
@@ -3274,7 +3274,7 @@ static int udc_pci_probe(
if (dev->virt_addr == NULL) {
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
kfree(dev);
- dev = 0;
+ dev = NULL;
retval = -EFAULT;
goto finished;
}
@@ -3282,7 +3282,7 @@ static int udc_pci_probe(
if (!pdev->irq) {
dev_err(&dev->pdev->dev, "irq not set\n");
kfree(dev);
- dev = 0;
+ dev = NULL;
retval = -ENODEV;
goto finished;
}
@@ -3290,7 +3290,7 @@ static int udc_pci_probe(
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
kfree(dev);
- dev = 0;
+ dev = NULL;
retval = -EBUSY;
goto finished;
}
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 9b913afb2e6d..274c60a970cd 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -231,6 +231,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_ops = {
+ .owner = THIS_MODULE,
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -239,15 +240,7 @@ static const struct file_operations proc_ops = {
static void create_debug_file(struct at91_udc *udc)
{
- struct proc_dir_entry *pde;
-
- pde = create_proc_entry (debug_filename, 0, NULL);
- udc->pde = pde;
- if (pde == NULL)
- return;
-
- pde->proc_fops = &proc_ops;
- pde->data = udc;
+ udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc);
}
static void remove_debug_file(struct at91_udc *udc)
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index e756023362c2..07e5a0b5dcda 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -649,7 +649,13 @@ static int usba_ep_disable(struct usb_ep *_ep)
if (!ep->desc) {
spin_unlock_irqrestore(&udc->lock, flags);
- DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+ /* REVISIT because this driver disables endpoints in
+ * reset_all_endpoints() before calling disconnect(),
+ * most gadget drivers would trigger this non-error ...
+ */
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN)
+ DBG(DBG_ERR, "ep_disable: %s not enabled\n",
+ ep->ep.name);
return -EINVAL;
}
ep->desc = NULL;
@@ -1032,8 +1038,6 @@ static struct usba_udc the_udc = {
.release = nop_release,
},
},
-
- .lock = SPIN_LOCK_UNLOCKED,
};
/*
@@ -1052,6 +1056,12 @@ static void reset_all_endpoints(struct usba_udc *udc)
request_complete(ep, req, -ECONNRESET);
}
+ /* NOTE: normally, the next call to the gadget driver is in
+ * charge of disabling endpoints... usually disconnect().
+ * The exception would be entering a high speed test mode.
+ *
+ * FIXME remove this code ... and retest thoroughly.
+ */
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
if (ep->desc) {
spin_unlock(&udc->lock);
@@ -1219,7 +1229,7 @@ static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
struct usb_ctrlrequest *crq)
{
- int retval = 0;;
+ int retval = 0;
switch (crq->bRequest) {
case USB_REQ_GET_STATUS: {
@@ -1693,6 +1703,14 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
reset_all_endpoints(udc);
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver->disconnect) {
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+
if (status & USBA_HIGH_SPEED) {
DBG(DBG_BUS, "High-speed bus reset detected\n");
udc->gadget.speed = USB_SPEED_HIGH;
@@ -1716,9 +1734,13 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
| USBA_DET_SUSPEND
| USBA_END_OF_RESUME));
+ /*
+ * Unclear why we hit this irregularly, e.g. in usbtest,
+ * but it's clearly harmless...
+ */
if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
- dev_warn(&udc->pdev->dev,
- "WARNING: EP0 configuration is invalid!\n");
+ dev_dbg(&udc->pdev->dev,
+ "ODD: EP0 configuration is invalid!\n");
}
spin_unlock(&udc->lock);
@@ -1751,9 +1773,11 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
reset_all_endpoints(udc);
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- spin_unlock(&udc->lock);
- udc->driver->disconnect(&udc->gadget);
- spin_lock(&udc->lock);
+ if (udc->driver->disconnect) {
+ spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
}
udc->vbus_prev = vbus;
}
@@ -1825,7 +1849,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!udc->pdev)
return -ENODEV;
- if (driver != udc->driver)
+ if (driver != udc->driver || !driver->unbind)
return -EINVAL;
if (udc->vbus_pin != -1)
@@ -1840,6 +1864,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
+ if (udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
+
driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
@@ -1879,6 +1906,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
goto err_get_hclk;
}
+ spin_lock_init(&udc->lock);
udc->pdev = pdev;
udc->pclk = pclk;
udc->hclk = hclk;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index bb93bdd76593..8d61ea67a817 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -235,10 +235,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define DEV_CONFIG_CDC
-#endif
-
#ifdef CONFIG_USB_GADGET_S3C2410
#define DEV_CONFIG_CDC
#endif
@@ -270,6 +266,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define DEV_CONFIG_SUBSET
+#endif
+
#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index bf3f946fd455..47bb9f09a1aa 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2307,6 +2307,29 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
return rc;
}
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+ int rc;
+
+ DBG(fsg, "bulk-in set wedge\n");
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ if (rc == -EAGAIN)
+ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+ while (rc != 0) {
+ if (rc != -EAGAIN) {
+ WARN(fsg, "usb_ep_set_wedge -> %d\n", rc);
+ rc = 0;
+ break;
+ }
+
+ /* Wait for a short time and then try again */
+ if (msleep_interruptible(100) != 0)
+ return -EINTR;
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ }
+ return rc;
+}
+
static int pad_with_zeros(struct fsg_dev *fsg)
{
struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
@@ -2957,7 +2980,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
* We aren't required to halt the OUT endpoint; instead
* we can simply accept and discard any data received
* until the next reset. */
- halt_bulk_in_endpoint(fsg);
+ wedge_bulk_in_endpoint(fsg);
set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
return -EINVAL;
}
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 64a592cbbe7b..be6613afedbf 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -127,7 +127,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* enabling the no-toggle interrupt mode would need an api hook */
mode = 0;
- max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+ max = get_unaligned_le16(&desc->wMaxPacketSize);
switch (max) {
case 64: mode++;
case 32: mode++;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 95f7662376f1..881d74c3d964 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2504,6 +2504,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
}
static const struct file_operations proc_ops = {
+ .owner = THIS_MODULE,
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -2512,11 +2513,7 @@ static const struct file_operations proc_ops = {
static void create_proc_file(void)
{
- struct proc_dir_entry *pde;
-
- pde = create_proc_entry (proc_filename, 0, NULL);
- if (pde)
- pde->proc_fops = &proc_ops;
+ proc_create(proc_filename, 0, NULL, &proc_ops);
}
static void remove_proc_file(void)
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
new file mode 100644
index 000000000000..499b7a23f351
--- /dev/null
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -0,0 +1,2403 @@
+/*
+ * Handles the Intel 27x USB Device Controller (UDC)
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/hardware.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/arch/udc.h>
+
+#include "pxa27x_udc.h"
+
+/*
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x
+ * series processors.
+ *
+ * Such controller drivers work with a gadget driver. The gadget driver
+ * returns descriptors, implements configuration and data protocols used
+ * by the host to interact with this device, and allocates endpoints to
+ * the different protocol interfaces. The controller driver virtualizes
+ * usb hardware so that the gadget drivers will be more portable.
+ *
+ * This UDC hardware wants to implement a bit too much USB protocol. The
+ * biggest issues are: that the endpoints have to be set up before the
+ * controller can be enabled (minor, and not uncommon); and each endpoint
+ * can only have one configuration, interface and alternative interface
+ * number (major, and very unusual). Once set up, these cannot be changed
+ * without a controller reset.
+ *
+ * The workaround is to setup all combinations necessary for the gadgets which
+ * will work with this driver. This is done in pxa_udc structure, statically.
+ * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep.
+ * (You could modify this if needed. Some drivers have a "fifo_mode" module
+ * parameter to facilitate such changes.)
+ *
+ * The combinations have been tested with these gadgets :
+ * - zero gadget
+ * - file storage gadget
+ * - ether gadget
+ *
+ * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is
+ * made of UDC's double buffering either. USB "On-The-Go" is not implemented.
+ *
+ * All the requests are handled the same way :
+ * - the drivers tries to handle the request directly to the IO
+ * - if the IO fifo is not big enough, the remaining is send/received in
+ * interrupt handling.
+ */
+
+#define DRIVER_VERSION "2008-04-18"
+#define DRIVER_DESC "PXA 27x USB Device Controller driver"
+
+static const char driver_name[] = "pxa27x_udc";
+static struct pxa_udc *the_controller;
+
+static void handle_ep(struct pxa_ep *ep);
+
+/*
+ * Debug filesystem
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+static int state_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ int pos = 0, ret;
+ u32 tmp;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ /* basic device status */
+ pos += seq_printf(s, DRIVER_DESC "\n"
+ "%s version: %s\nGadget driver: %s\n",
+ driver_name, DRIVER_VERSION,
+ udc->driver ? udc->driver->driver.name : "(none)");
+
+ tmp = udc_readl(udc, UDCCR);
+ pos += seq_printf(s,
+ "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), "
+ "con=%d,inter=%d,altinter=%d\n", tmp,
+ (tmp & UDCCR_OEN) ? " oen":"",
+ (tmp & UDCCR_AALTHNP) ? " aalthnp":"",
+ (tmp & UDCCR_AHNP) ? " rem" : "",
+ (tmp & UDCCR_BHNP) ? " rstir" : "",
+ (tmp & UDCCR_DWRE) ? " dwre" : "",
+ (tmp & UDCCR_SMAC) ? " smac" : "",
+ (tmp & UDCCR_EMCE) ? " emce" : "",
+ (tmp & UDCCR_UDR) ? " udr" : "",
+ (tmp & UDCCR_UDA) ? " uda" : "",
+ (tmp & UDCCR_UDE) ? " ude" : "",
+ (tmp & UDCCR_ACN) >> UDCCR_ACN_S,
+ (tmp & UDCCR_AIN) >> UDCCR_AIN_S,
+ (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
+ /* registers for device and ep0 */
+ pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
+ udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
+ pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
+ udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
+ pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
+ pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, "
+ "reconfig=%lu\n",
+ udc->stats.irqs_reset, udc->stats.irqs_suspend,
+ udc->stats.irqs_resume, udc->stats.irqs_reconfig);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int queues_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ struct pxa_ep *ep;
+ struct pxa27x_request *req;
+ int pos = 0, i, maxpkt, ret;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ /* dump endpoint queues */
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ maxpkt = ep->fifo_size;
+ pos += seq_printf(s, "%-12s max_pkt=%d %s\n",
+ EPNAME(ep), maxpkt, "pio");
+
+ if (list_empty(&ep->queue)) {
+ pos += seq_printf(s, "\t(nothing queued)\n");
+ continue;
+ }
+
+ list_for_each_entry(req, &ep->queue, queue) {
+ pos += seq_printf(s, "\treq %p len %d/%d buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int eps_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ struct pxa_ep *ep;
+ int pos = 0, i, ret;
+ u32 tmp;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ ep = &udc->pxa_ep[0];
+ tmp = udc_ep_readl(ep, UDCCSR);
+ pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp,
+ (tmp & UDCCSR0_SA) ? " sa" : "",
+ (tmp & UDCCSR0_RNE) ? " rne" : "",
+ (tmp & UDCCSR0_FST) ? " fst" : "",
+ (tmp & UDCCSR0_SST) ? " sst" : "",
+ (tmp & UDCCSR0_DME) ? " dme" : "",
+ (tmp & UDCCSR0_IPR) ? " ipr" : "",
+ (tmp & UDCCSR0_OPC) ? " opc" : "");
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR);
+ pos += seq_printf(s, "%-12s: "
+ "IN %lu(%lu reqs), OUT %lu(%lu reqs), "
+ "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, "
+ "udcbcr=%d\n",
+ EPNAME(ep),
+ ep->stats.in_bytes, ep->stats.in_ops,
+ ep->stats.out_bytes, ep->stats.out_ops,
+ ep->stats.irqs,
+ tmp, udc_ep_readl(ep, UDCCSR),
+ udc_ep_readl(ep, UDCBCR));
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int eps_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, eps_dbg_show, inode->i_private);
+}
+
+static int queues_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, queues_dbg_show, inode->i_private);
+}
+
+static int state_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, state_dbg_show, inode->i_private);
+}
+
+static const struct file_operations state_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = state_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static const struct file_operations queues_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = queues_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static const struct file_operations eps_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = eps_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static void pxa_init_debugfs(struct pxa_udc *udc)
+{
+ struct dentry *root, *state, *queues, *eps;
+
+ root = debugfs_create_dir(udc->gadget.name, NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+
+ state = debugfs_create_file("udcstate", 0400, root, udc,
+ &state_dbg_fops);
+ if (!state)
+ goto err_state;
+ queues = debugfs_create_file("queues", 0400, root, udc,
+ &queues_dbg_fops);
+ if (!queues)
+ goto err_queues;
+ eps = debugfs_create_file("epstate", 0400, root, udc,
+ &eps_dbg_fops);
+ if (!queues)
+ goto err_eps;
+
+ udc->debugfs_root = root;
+ udc->debugfs_state = state;
+ udc->debugfs_queues = queues;
+ udc->debugfs_eps = eps;
+ return;
+err_eps:
+ debugfs_remove(eps);
+err_queues:
+ debugfs_remove(queues);
+err_state:
+ debugfs_remove(root);
+err_root:
+ dev_err(udc->dev, "debugfs is not available\n");
+}
+
+static void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+ debugfs_remove(udc->debugfs_eps);
+ debugfs_remove(udc->debugfs_queues);
+ debugfs_remove(udc->debugfs_state);
+ debugfs_remove(udc->debugfs_root);
+ udc->debugfs_eps = NULL;
+ udc->debugfs_queues = NULL;
+ udc->debugfs_state = NULL;
+ udc->debugfs_root = NULL;
+}
+
+#else
+static inline void pxa_init_debugfs(struct pxa_udc *udc)
+{
+}
+
+static inline void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+}
+#endif
+
+/**
+ * is_match_usb_pxa - check if usb_ep and pxa_ep match
+ * @udc_usb_ep: usb endpoint
+ * @ep: pxa endpoint
+ * @config: configuration required in pxa_ep
+ * @interface: interface required in pxa_ep
+ * @altsetting: altsetting required in pxa_ep
+ *
+ * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise
+ */
+static int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep,
+ int config, int interface, int altsetting)
+{
+ if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr)
+ return 0;
+ if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in)
+ return 0;
+ if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type)
+ return 0;
+ if ((ep->config != config) || (ep->interface != interface)
+ || (ep->alternate != altsetting))
+ return 0;
+ return 1;
+}
+
+/**
+ * find_pxa_ep - find pxa_ep structure matching udc_usb_ep
+ * @udc: pxa udc
+ * @udc_usb_ep: udc_usb_ep structure
+ *
+ * Match udc_usb_ep and all pxa_ep available, to see if one matches.
+ * This is necessary because of the strong pxa hardware restriction requiring
+ * that once pxa endpoints are initialized, their configuration is freezed, and
+ * no change can be made to their address, direction, or in which configuration,
+ * interface or altsetting they are active ... which differs from more usual
+ * models which have endpoints be roughly just addressable fifos, and leave
+ * configuration events up to gadget drivers (like all control messages).
+ *
+ * Note that there is still a blurred point here :
+ * - we rely on UDCCR register "active interface" and "active altsetting".
+ * This is a nonsense in regard of USB spec, where multiple interfaces are
+ * active at the same time.
+ * - if we knew for sure that the pxa can handle multiple interface at the
+ * same time, assuming Intel's Developer Guide is wrong, this function
+ * should be reviewed, and a cache of couples (iface, altsetting) should
+ * be kept in the pxa_udc structure. In this case this function would match
+ * against the cache of couples instead of the "last altsetting" set up.
+ *
+ * Returns the matched pxa_ep structure or NULL if none found
+ */
+static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
+ struct udc_usb_ep *udc_usb_ep)
+{
+ int i;
+ struct pxa_ep *ep;
+ int cfg = udc->config;
+ int iface = udc->last_interface;
+ int alt = udc->last_alternate;
+
+ if (udc_usb_ep == &udc->udc_usb_ep[0])
+ return &udc->pxa_ep[0];
+
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt))
+ return ep;
+ }
+ return NULL;
+}
+
+/**
+ * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
+ * @udc: pxa udc
+ *
+ * Context: in_interrupt()
+ *
+ * Updates all pxa_ep fields in udc_usb_ep structures, if this field was
+ * previously set up (and is not NULL). The update is necessary is a
+ * configuration change or altsetting change was issued by the USB host.
+ */
+static void update_pxa_ep_matches(struct pxa_udc *udc)
+{
+ int i;
+ struct udc_usb_ep *udc_usb_ep;
+
+ for (i = 1; i < NR_USB_ENDPOINTS; i++) {
+ udc_usb_ep = &udc->udc_usb_ep[i];
+ if (udc_usb_ep->pxa_ep)
+ udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep);
+ }
+}
+
+/**
+ * pio_irq_enable - Enables irq generation for one endpoint
+ * @ep: udc endpoint
+ */
+static void pio_irq_enable(struct pxa_ep *ep)
+{
+ struct pxa_udc *udc = ep->dev;
+ int index = EPIDX(ep);
+ u32 udcicr0 = udc_readl(udc, UDCICR0);
+ u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+ if (index < 16)
+ udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2)));
+ else
+ udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2)));
+}
+
+/**
+ * pio_irq_disable - Disables irq generation for one endpoint
+ * @ep: udc endpoint
+ * @index: endpoint number
+ */
+static void pio_irq_disable(struct pxa_ep *ep)
+{
+ struct pxa_udc *udc = ep->dev;
+ int index = EPIDX(ep);
+ u32 udcicr0 = udc_readl(udc, UDCICR0);
+ u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+ if (index < 16)
+ udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2)));
+ else
+ udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2)));
+}
+
+/**
+ * udc_set_mask_UDCCR - set bits in UDCCR
+ * @udc: udc device
+ * @mask: bits to set in UDCCR
+ *
+ * Sets bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ udc_writel(udc, UDCCR,
+ (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * udc_clear_mask_UDCCR - clears bits in UDCCR
+ * @udc: udc device
+ * @mask: bit to clear in UDCCR
+ *
+ * Clears bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ udc_writel(udc, UDCCR,
+ (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * ep_count_bytes_remain - get how many bytes in udc endpoint
+ * @ep: udc endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP)
+ */
+static int ep_count_bytes_remain(struct pxa_ep *ep)
+{
+ if (ep->dir_in)
+ return -EOPNOTSUPP;
+ return udc_ep_readl(ep, UDCBCR) & 0x3ff;
+}
+
+/**
+ * ep_is_empty - checks if ep has byte ready for reading
+ * @ep: udc endpoint
+ *
+ * If endpoint is the control endpoint, checks if there are bytes in the
+ * control endpoint fifo. If endpoint is a data endpoint, checks if bytes
+ * are ready for reading on OUT endpoint.
+ *
+ * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint
+ */
+static int ep_is_empty(struct pxa_ep *ep)
+{
+ int ret;
+
+ if (!is_ep0(ep) && ep->dir_in)
+ return -EOPNOTSUPP;
+ if (is_ep0(ep))
+ ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE);
+ else
+ ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE);
+ return ret;
+}
+
+/**
+ * ep_is_full - checks if ep has place to write bytes
+ * @ep: udc endpoint
+ *
+ * If endpoint is not the control endpoint and is an IN endpoint, checks if
+ * there is place to write bytes into the endpoint.
+ *
+ * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint
+ */
+static int ep_is_full(struct pxa_ep *ep)
+{
+ if (is_ep0(ep))
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR);
+ if (!ep->dir_in)
+ return -EOPNOTSUPP;
+ return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF));
+}
+
+/**
+ * epout_has_pkt - checks if OUT endpoint fifo has a packet available
+ * @ep: pxa endpoint
+ *
+ * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep.
+ */
+static int epout_has_pkt(struct pxa_ep *ep)
+{
+ if (!is_ep0(ep) && ep->dir_in)
+ return -EOPNOTSUPP;
+ if (is_ep0(ep))
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC);
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC);
+}
+
+/**
+ * set_ep0state - Set ep0 automata state
+ * @dev: udc device
+ * @state: state
+ */
+static void set_ep0state(struct pxa_udc *udc, int state)
+{
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ char *old_stname = EP0_STNAME(udc);
+
+ udc->ep0state = state;
+ ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname,
+ EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR),
+ udc_ep_readl(ep, UDCBCR));
+}
+
+/**
+ * ep0_idle - Put control endpoint into idle state
+ * @dev: udc device
+ */
+static void ep0_idle(struct pxa_udc *dev)
+{
+ set_ep0state(dev, WAIT_FOR_SETUP);
+}
+
+/**
+ * inc_ep_stats_reqs - Update ep stats counts
+ * @ep: physical endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ *
+ */
+static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in)
+{
+ if (is_in)
+ ep->stats.in_ops++;
+ else
+ ep->stats.out_ops++;
+}
+
+/**
+ * inc_ep_stats_bytes - Update ep stats counts
+ * @ep: physical endpoint
+ * @count: bytes transfered on endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ */
+static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
+{
+ if (is_in)
+ ep->stats.in_bytes += count;
+ else
+ ep->stats.out_bytes += count;
+}
+
+/**
+ * pxa_ep_setup - Sets up an usb physical endpoint
+ * @ep: pxa27x physical endpoint
+ *
+ * Find the physical pxa27x ep, and setup its UDCCR
+ */
+static __init void pxa_ep_setup(struct pxa_ep *ep)
+{
+ u32 new_udccr;
+
+ new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN)
+ | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN)
+ | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN)
+ | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN)
+ | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET)
+ | ((ep->dir_in) ? UDCCONR_ED : 0)
+ | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS)
+ | UDCCONR_EE;
+
+ udc_ep_writel(ep, UDCCR, new_udccr);
+}
+
+/**
+ * pxa_eps_setup - Sets up all usb physical endpoints
+ * @dev: udc device
+ *
+ * Setup all pxa physical endpoints, except ep0
+ */
+static __init void pxa_eps_setup(struct pxa_udc *dev)
+{
+ unsigned int i;
+
+ dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev);
+
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++)
+ pxa_ep_setup(&dev->pxa_ep[i]);
+}
+
+/**
+ * pxa_ep_alloc_request - Allocate usb request
+ * @_ep: usb endpoint
+ * @gfp_flags:
+ *
+ * For the pxa27x, these can just wrap kmalloc/kfree. gadget drivers
+ * must still pass correctly initialized endpoints, since other controller
+ * drivers may care about how it's currently set up (dma issues etc).
+ */
+static struct usb_request *
+pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct pxa27x_request *req;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req || !_ep)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->in_use = 0;
+ req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+ return &req->req;
+}
+
+/**
+ * pxa_ep_free_request - Free usb request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Wrapper around kfree to free _req
+ */
+static void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct pxa27x_request *req;
+
+ req = container_of(_req, struct pxa27x_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/**
+ * ep_add_request - add a request to the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Queues the request in the endpoint's queue, and enables the interrupts
+ * on the endpoint.
+ */
+static void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ if (unlikely(!req))
+ return;
+ ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+ req->req.length, udc_ep_readl(ep, UDCCSR));
+
+ req->in_use = 1;
+ list_add_tail(&req->queue, &ep->queue);
+ pio_irq_enable(ep);
+}
+
+/**
+ * ep_del_request - removes a request from the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Unqueue the request from the endpoint's queue. If there are no more requests
+ * on the endpoint, and if it's not the control endpoint, interrupts are
+ * disabled on the endpoint.
+ */
+static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ if (unlikely(!req))
+ return;
+ ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+ req->req.length, udc_ep_readl(ep, UDCCSR));
+
+ list_del_init(&req->queue);
+ req->in_use = 0;
+ if (!is_ep0(ep) && list_empty(&ep->queue))
+ pio_irq_disable(ep);
+}
+
+/**
+ * req_done - Complete an usb request
+ * @ep: pxa physical endpoint
+ * @req: pxa request
+ * @status: usb request status sent to gadget API
+ *
+ * Context: ep->lock held
+ *
+ * Retire a pxa27x usb request. Endpoint must be locked.
+ */
+static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
+{
+ ep_del_request(ep, req);
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (status && status != -ESHUTDOWN)
+ ep_dbg(ep, "complete req %p stat %d len %u/%u\n",
+ &req->req, status,
+ req->req.actual, req->req.length);
+
+ req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
+}
+
+/**
+ * ep_end_out_req - Ends control endpoint in request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint in request (completes usb request).
+ */
+static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ inc_ep_stats_reqs(ep, !USB_DIR_IN);
+ req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_out_req - Ends control endpoint in request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint in request (completes usb request), and puts
+ * control endpoint into idle state
+ */
+static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ set_ep0state(ep->dev, OUT_STATUS_STAGE);
+ ep_end_out_req(ep, req);
+ ep0_idle(ep->dev);
+}
+
+/**
+ * ep_end_in_req - Ends endpoint out request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint out request (completes usb request).
+ */
+static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ inc_ep_stats_reqs(ep, USB_DIR_IN);
+ req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_in_req - Ends control endpoint out request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint out request (completes usb request), and puts
+ * control endpoint into status state
+ */
+static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ struct pxa_udc *udc = ep->dev;
+
+ set_ep0state(udc, IN_STATUS_STAGE);
+ ep_end_in_req(ep, req);
+}
+
+/**
+ * nuke - Dequeue all requests
+ * @ep: pxa endpoint
+ * @status: usb request status
+ *
+ * Context: ep->lock held
+ *
+ * Dequeues all requests on an endpoint. As a side effect, interrupts will be
+ * disabled on that endpoint (because no more requests).
+ */
+static void nuke(struct pxa_ep *ep, int status)
+{
+ struct pxa27x_request *req;
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+ req_done(ep, req, status);
+ }
+}
+
+/**
+ * read_packet - transfer 1 packet from an OUT endpoint into request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Takes bytes from OUT endpoint and transfers them info the usb request.
+ * If there is less space in request than bytes received in OUT endpoint,
+ * bytes are left in the OUT endpoint.
+ *
+ * Returns how many bytes were actually transfered
+ */
+static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ u32 *buf;
+ int bytes_ep, bufferspace, count, i;
+
+ bytes_ep = ep_count_bytes_remain(ep);
+ bufferspace = req->req.length - req->req.actual;
+
+ buf = (u32 *)(req->req.buf + req->req.actual);
+ prefetchw(buf);
+
+ if (likely(!ep_is_empty(ep)))
+ count = min(bytes_ep, bufferspace);
+ else /* zlp */
+ count = 0;
+
+ for (i = count; i > 0; i -= 4)
+ *buf++ = udc_ep_readl(ep, UDCDR);
+ req->req.actual += count;
+
+ udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+
+ return count;
+}
+
+/**
+ * write_packet - transfer 1 packet from request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ * @max: max bytes that fit into endpoint
+ *
+ * Takes bytes from usb request, and transfers them into the physical
+ * endpoint. If there are no bytes to transfer, doesn't write anything
+ * to physical endpoint.
+ *
+ * Returns how many bytes were actually transfered.
+ */
+static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned int max)
+{
+ int length, count, remain, i;
+ u32 *buf;
+ u8 *buf_8;
+
+ buf = (u32 *)(req->req.buf + req->req.actual);
+ prefetch(buf);
+
+ length = min(req->req.length - req->req.actual, max);
+ req->req.actual += length;
+
+ remain = length & 0x3;
+ count = length & ~(0x3);
+ for (i = count; i > 0 ; i -= 4)
+ udc_ep_writel(ep, UDCDR, *buf++);
+
+ buf_8 = (u8 *)buf;
+ for (i = remain; i > 0; i--)
+ udc_ep_writeb(ep, UDCDR, *buf_8++);
+
+ ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain,
+ udc_ep_readl(ep, UDCCSR));
+
+ return length;
+}
+
+/**
+ * read_fifo - Transfer packets from OUT endpoint into usb request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Unload as many packets as possible from the fifo we use for usb OUT
+ * transfers and put them into the request. Caller should have made sure
+ * there's at least one packet ready.
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if the request completed, 0 otherwise
+ */
+static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ int count, is_short, completed = 0;
+
+ while (epout_has_pkt(ep)) {
+ count = read_packet(ep, req);
+ inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+ is_short = (count < ep->fifo_size);
+ ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+ udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+ &req->req, req->req.actual, req->req.length);
+
+ /* completion */
+ if (is_short || req->req.actual == req->req.length) {
+ completed = 1;
+ break;
+ }
+ /* finished that packet. the next one may be waiting... */
+ }
+ return completed;
+}
+
+/**
+ * write_fifo - transfer packets from usb request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: pxa usb request
+ *
+ * Write to an IN endpoint fifo, as many packets as possible.
+ * irqs will use this to write the rest later.
+ * caller guarantees at least one packet buffer is ready (or a zlp).
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if request fully transfered, 0 if partial transfer
+ */
+static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ unsigned max;
+ int count, is_short, is_last = 0, completed = 0, totcount = 0;
+ u32 udccsr;
+
+ max = ep->fifo_size;
+ do {
+ is_short = 0;
+
+ udccsr = udc_ep_readl(ep, UDCCSR);
+ if (udccsr & UDCCSR_PC) {
+ ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
+ udccsr);
+ udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+ }
+ if (udccsr & UDCCSR_TRN) {
+ ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
+ udccsr);
+ udc_ep_writel(ep, UDCCSR, UDCCSR_TRN);
+ }
+
+ count = write_packet(ep, req, max);
+ inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+ totcount += count;
+
+ /* last packet is usually short (or a zlp) */
+ if (unlikely(count < max)) {
+ is_last = 1;
+ is_short = 1;
+ } else {
+ if (likely(req->req.length > req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ /* interrupt/iso maxpacket may not fill the fifo */
+ is_short = unlikely(max < ep->fifo_size);
+ }
+
+ if (is_short)
+ udc_ep_writel(ep, UDCCSR, UDCCSR_SP);
+
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ completed = 1;
+ break;
+ }
+ } while (!ep_is_full(ep));
+
+ ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n",
+ totcount, is_last ? "/L" : "", is_short ? "/S" : "",
+ req->req.length - req->req.actual, &req->req);
+
+ return completed;
+}
+
+/**
+ * read_ep0_fifo - Transfer packets from control endpoint into usb request
+ * @ep: control endpoint
+ * @req: pxa usb request
+ *
+ * Special ep0 version of the above read_fifo. Reads as many bytes from control
+ * endpoint as can be read, and stores them into usb request (limited by request
+ * maximum length).
+ *
+ * Returns 0 if usb request only partially filled, 1 if fully filled
+ */
+static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ int count, is_short, completed = 0;
+
+ while (epout_has_pkt(ep)) {
+ count = read_packet(ep, req);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+ inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+ is_short = (count < ep->fifo_size);
+ ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+ udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+ &req->req, req->req.actual, req->req.length);
+
+ if (is_short || req->req.actual >= req->req.length) {
+ completed = 1;
+ break;
+ }
+ }
+
+ return completed;
+}
+
+/**
+ * write_ep0_fifo - Send a request to control endpoint (ep0 in)
+ * @ep: control endpoint
+ * @req: request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Sends a request (or a part of the request) to the control endpoint (ep0 in).
+ * If the request doesn't fit, the remaining part will be sent from irq.
+ * The request is considered fully written only if either :
+ * - last write transfered all remaining bytes, but fifo was not fully filled
+ * - last write was a 0 length write
+ *
+ * Returns 1 if request fully written, 0 if request only partially sent
+ */
+static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ unsigned count;
+ int is_last, is_short;
+
+ count = write_packet(ep, req, EP0_FIFO_SIZE);
+ inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+
+ is_short = (count < EP0_FIFO_SIZE);
+ is_last = ((count == 0) || (count < EP0_FIFO_SIZE));
+
+ /* Sends either a short packet or a 0 length packet */
+ if (unlikely(is_short))
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR);
+
+ ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
+ count, is_short ? "/S" : "", is_last ? "/L" : "",
+ req->req.length - req->req.actual,
+ &req->req, udc_ep_readl(ep, UDCCSR));
+
+ return is_last;
+}
+
+/**
+ * pxa_ep_queue - Queue a request into an IN endpoint
+ * @_ep: usb endpoint
+ * @_req: usb request
+ * @gfp_flags: flags
+ *
+ * Context: normally called when !in_interrupt, but callable when in_interrupt()
+ * in the special case of ep0 setup :
+ * (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
+ *
+ * Returns 0 if succedeed, error otherwise
+ */
+static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa_ep *ep;
+ struct pxa27x_request *req;
+ struct pxa_udc *dev;
+ unsigned long flags;
+ int rc = 0;
+ int is_first_req;
+ unsigned length;
+
+ req = container_of(_req, struct pxa27x_request, req);
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+ if (unlikely(!_req || !_req->complete || !_req->buf))
+ return -EINVAL;
+
+ if (unlikely(!_ep))
+ return -EINVAL;
+
+ dev = udc_usb_ep->dev;
+ ep = udc_usb_ep->pxa_ep;
+ if (unlikely(!ep))
+ return -EINVAL;
+
+ dev = ep->dev;
+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ ep_dbg(ep, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ /* iso is always one packet per request, that's the only way
+ * we can report per-packet status. that also helps with dma.
+ */
+ if (unlikely(EPXFERTYPE_is_ISO(ep)
+ && req->req.length > ep->fifo_size))
+ return -EMSGSIZE;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ is_first_req = list_empty(&ep->queue);
+ ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
+ _req, is_first_req ? "yes" : "no",
+ _req->length, _req->buf);
+
+ if (!ep->enabled) {
+ _req->status = -ESHUTDOWN;
+ rc = -ESHUTDOWN;
+ goto out;
+ }
+
+ if (req->in_use) {
+ ep_err(ep, "refusing to queue req %p (already queued)\n", req);
+ goto out;
+ }
+
+ length = _req->length;
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ ep_add_request(ep, req);
+
+ if (is_ep0(ep)) {
+ switch (dev->ep0state) {
+ case WAIT_ACK_SET_CONF_INTERF:
+ if (length == 0) {
+ ep_end_in_req(ep, req);
+ } else {
+ ep_err(ep, "got a request of %d bytes while"
+ "in state WATI_ACK_SET_CONF_INTERF\n",
+ length);
+ ep_del_request(ep, req);
+ rc = -EL2HLT;
+ }
+ ep0_idle(ep->dev);
+ break;
+ case IN_DATA_STAGE:
+ if (!ep_is_full(ep))
+ if (write_ep0_fifo(ep, req))
+ ep0_end_in_req(ep, req);
+ break;
+ case OUT_DATA_STAGE:
+ if ((length == 0) || !epout_has_pkt(ep))
+ if (read_ep0_fifo(ep, req))
+ ep0_end_out_req(ep, req);
+ break;
+ default:
+ ep_err(ep, "odd state %s to send me a request\n",
+ EP0_STNAME(ep->dev));
+ ep_del_request(ep, req);
+ rc = -EL2HLT;
+ break;
+ }
+ } else {
+ handle_ep(ep);
+ }
+
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_dequeue - Dequeue one request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Return 0 if no error, -EINVAL or -ECONNRESET otherwise
+ */
+static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa27x_request *req;
+ unsigned long flags;
+ int rc;
+
+ if (!_ep)
+ return -EINVAL;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+
+ rc = -EINVAL;
+ if (&req->req != _req)
+ goto out;
+
+ rc = 0;
+ req_done(ep, req, -ECONNRESET);
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_set_halt - Halts operations on one endpoint
+ * @_ep: usb endpoint
+ * @value:
+ *
+ * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise
+ */
+static int pxa_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+ int rc;
+
+
+ if (!_ep)
+ return -EINVAL;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -EINVAL;
+
+ if (value == 0) {
+ /*
+ * This path (reset toggle+halt) is needed to implement
+ * SET_INTERFACE on normal hardware. but it can't be
+ * done from software on the PXA UDC, and the hardware
+ * forgets to do it as part of SET_INTERFACE automagic.
+ */
+ ep_dbg(ep, "only host can clear halt\n");
+ return -EROFS;
+ }
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ rc = -EAGAIN;
+ if (ep->dir_in && (ep_is_full(ep) || !list_empty(&ep->queue)))
+ goto out;
+
+ /* FST, FEF bits are the same for control and non control endpoints */
+ rc = 0;
+ udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF);
+ if (is_ep0(ep))
+ set_ep0state(ep->dev, STALL);
+
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_fifo_status - Get how many bytes in physical endpoint
+ * @_ep: usb endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos.
+ */
+static int pxa_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+
+ if (!_ep)
+ return -ENODEV;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -ENODEV;
+
+ if (ep->dir_in)
+ return -EOPNOTSUPP;
+ if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep))
+ return 0;
+ else
+ return ep_count_bytes_remain(ep) + 1;
+}
+
+/**
+ * pxa_ep_fifo_flush - Flushes one endpoint
+ * @_ep: usb endpoint
+ *
+ * Discards all data in one endpoint(IN or OUT), except control endpoint.
+ */
+static void pxa_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+
+ if (!_ep)
+ return;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ if (unlikely(!list_empty(&ep->queue)))
+ ep_dbg(ep, "called while queue list not empty\n");
+ ep_dbg(ep, "called\n");
+
+ /* for OUT, just read and discard the FIFO contents. */
+ if (!ep->dir_in) {
+ while (!ep_is_empty(ep))
+ udc_ep_readl(ep, UDCDR);
+ } else {
+ /* most IN status is the same, but ISO can't stall */
+ udc_ep_writel(ep, UDCCSR,
+ UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
+ | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
+ }
+
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ return;
+}
+
+/**
+ * pxa_ep_enable - Enables usb endpoint
+ * @_ep: usb endpoint
+ * @desc: usb endpoint descriptor
+ *
+ * Nothing much to do here, as ep configuration is done once and for all
+ * before udc is enabled. After udc enable, no physical endpoint configuration
+ * can be changed.
+ * Function makes sanity checks and flushes the endpoint.
+ */
+static int pxa_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa_udc *udc;
+
+ if (!_ep || !desc)
+ return -EINVAL;
+
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ if (udc_usb_ep->pxa_ep) {
+ ep = udc_usb_ep->pxa_ep;
+ ep_warn(ep, "usb_ep %s already enabled, doing nothing\n",
+ _ep->name);
+ } else {
+ ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep);
+ }
+
+ if (!ep || is_ep0(ep)) {
+ dev_err(udc_usb_ep->dev->dev,
+ "unable to match pxa_ep for ep %s\n",
+ _ep->name);
+ return -EINVAL;
+ }
+
+ if ((desc->bDescriptorType != USB_DT_ENDPOINT)
+ || (ep->type != usb_endpoint_type(desc))) {
+ ep_err(ep, "type mismatch\n");
+ return -EINVAL;
+ }
+
+ if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
+ ep_err(ep, "bad maxpacket\n");
+ return -ERANGE;
+ }
+
+ udc_usb_ep->pxa_ep = ep;
+ udc = ep->dev;
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ ep_err(ep, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ ep->enabled = 1;
+
+ /* flush fifo (mostly for OUT buffers) */
+ pxa_ep_fifo_flush(_ep);
+
+ ep_dbg(ep, "enabled\n");
+ return 0;
+}
+
+/**
+ * pxa_ep_disable - Disable usb endpoint
+ * @_ep: usb endpoint
+ *
+ * Same as for pxa_ep_enable, no physical endpoint configuration can be
+ * changed.
+ * Function flushes the endpoint and related requests.
+ */
+static int pxa_ep_disable(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+
+ if (!_ep)
+ return -EINVAL;
+
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ ep->enabled = 0;
+ nuke(ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ pxa_ep_fifo_flush(_ep);
+ udc_usb_ep->pxa_ep = NULL;
+
+ ep_dbg(ep, "disabled\n");
+ return 0;
+}
+
+static struct usb_ep_ops pxa_ep_ops = {
+ .enable = pxa_ep_enable,
+ .disable = pxa_ep_disable,
+
+ .alloc_request = pxa_ep_alloc_request,
+ .free_request = pxa_ep_free_request,
+
+ .queue = pxa_ep_queue,
+ .dequeue = pxa_ep_dequeue,
+
+ .set_halt = pxa_ep_set_halt,
+ .fifo_status = pxa_ep_fifo_status,
+ .fifo_flush = pxa_ep_fifo_flush,
+};
+
+
+/**
+ * pxa_udc_get_frame - Returns usb frame number
+ * @_gadget: usb gadget
+ */
+static int pxa_udc_get_frame(struct usb_gadget *_gadget)
+{
+ struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+ return (udc_readl(udc, UDCFNR) & 0x7ff);
+}
+
+/**
+ * pxa_udc_wakeup - Force udc device out of suspend
+ * @_gadget: usb gadget
+ *
+ * Returns 0 if succesfull, error code otherwise
+ */
+static int pxa_udc_wakeup(struct usb_gadget *_gadget)
+{
+ struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+ /* host may not have enabled remote wakeup */
+ if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0)
+ return -EHOSTUNREACH;
+ udc_set_mask_UDCCR(udc, UDCCR_UDR);
+ return 0;
+}
+
+static const struct usb_gadget_ops pxa_udc_ops = {
+ .get_frame = pxa_udc_get_frame,
+ .wakeup = pxa_udc_wakeup,
+ /* current versions must always be self-powered */
+};
+
+/**
+ * udc_disable - disable udc device controller
+ * @udc: udc device
+ *
+ * Disables the udc device : disables clocks, udc interrupts, control endpoint
+ * interrupts.
+ */
+static void udc_disable(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+ clk_disable(udc->clk);
+
+ ep0_idle(udc);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+/**
+ * udc_init_data - Initialize udc device data structures
+ * @dev: udc device
+ *
+ * Initializes gadget endpoint list, endpoints locks. No action is taken
+ * on the hardware.
+ */
+static __init void udc_init_data(struct pxa_udc *dev)
+{
+ int i;
+ struct pxa_ep *ep;
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+ dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
+ ep0_idle(dev);
+
+ /* PXA endpoints init */
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &dev->pxa_ep[i];
+
+ ep->enabled = is_ep0(ep);
+ INIT_LIST_HEAD(&ep->queue);
+ spin_lock_init(&ep->lock);
+ }
+
+ /* USB endpoints init */
+ for (i = 0; i < NR_USB_ENDPOINTS; i++)
+ if (i != 0)
+ list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
+ &dev->gadget.ep_list);
+}
+
+/**
+ * udc_enable - Enables the udc device
+ * @dev: udc device
+ *
+ * Enables the udc device : enables clocks, udc interrupts, control endpoint
+ * interrupts, sets usb as UDC client and setups endpoints.
+ */
+static void udc_enable(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+ udc_writel(udc, UP2OCR, UP2OCR_HXOE);
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+
+ clk_enable(udc->clk);
+
+ ep0_idle(udc);
+ udc->gadget.speed = USB_SPEED_FULL;
+ memset(&udc->stats, 0, sizeof(udc->stats));
+
+ udc_set_mask_UDCCR(udc, UDCCR_UDE);
+ udelay(2);
+ if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
+ dev_err(udc->dev, "Configuration errors, udc disabled\n");
+
+ /*
+ * Caller must be able to sleep in order to cope with startup transients
+ */
+ msleep(100);
+
+ /* enable suspend/resume and reset irqs */
+ udc_writel(udc, UDCICR1,
+ UDCICR1_IECC | UDCICR1_IERU
+ | UDCICR1_IESU | UDCICR1_IERS);
+
+ /* enable ep0 irqs */
+ pio_irq_enable(&udc->pxa_ep[0]);
+
+ dev_info(udc->dev, "UDC connecting\n");
+ if (udc->mach->udc_command)
+ udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
+/**
+ * usb_gadget_register_driver - Register gadget driver
+ * @driver: gadget driver
+ *
+ * When a driver is successfully registered, it will receive control requests
+ * including set_configuration(), which enables non-control requests. Then
+ * usb traffic follows until a disconnect is reported. Then a host may connect
+ * again, or the driver might get unbound.
+ *
+ * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct pxa_udc *udc = the_controller;
+ int retval;
+
+ if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind
+ || !driver->disconnect || !driver->setup)
+ return -EINVAL;
+ if (!udc)
+ return -ENODEV;
+ if (udc->driver)
+ return -EBUSY;
+
+ /* first hook up the driver ... */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&udc->gadget.dev);
+ if (retval) {
+ dev_err(udc->dev, "device_add error %d\n", retval);
+ goto add_fail;
+ }
+ retval = driver->bind(&udc->gadget);
+ if (retval) {
+ dev_err(udc->dev, "bind to driver %s --> error %d\n",
+ driver->driver.name, retval);
+ goto bind_fail;
+ }
+ dev_dbg(udc->dev, "registered gadget driver '%s'\n",
+ driver->driver.name);
+
+ udc_enable(udc);
+ return 0;
+
+bind_fail:
+ device_del(&udc->gadget.dev);
+add_fail:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+
+/**
+ * stop_activity - Stops udc endpoints
+ * @udc: udc device
+ * @driver: gadget driver
+ *
+ * Disables all udc endpoints (even control endpoint), report disconnect to
+ * the gadget user.
+ */
+static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
+{
+ int i;
+
+ /* don't disconnect drivers more than once */
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+ for (i = 0; i < NR_USB_ENDPOINTS; i++)
+ pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
+
+ if (driver)
+ driver->disconnect(&udc->gadget);
+}
+
+/**
+ * usb_gadget_unregister_driver - Unregister the gadget driver
+ * @driver: gadget driver
+ *
+ * Returns 0 if no error, -ENODEV, -EINVAL otherwise
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct pxa_udc *udc = the_controller;
+
+ if (!udc)
+ return -ENODEV;
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ stop_activity(udc, driver);
+ udc_disable(udc);
+
+ driver->unbind(&udc->gadget);
+ udc->driver = NULL;
+
+ device_del(&udc->gadget.dev);
+
+ dev_info(udc->dev, "unregistered gadget driver '%s'\n",
+ driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/**
+ * handle_ep0_ctrl_req - handle control endpoint control request
+ * @udc: udc device
+ * @req: control request
+ */
+static void handle_ep0_ctrl_req(struct pxa_udc *udc,
+ struct pxa27x_request *req)
+{
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ union {
+ struct usb_ctrlrequest r;
+ u32 word[2];
+ } u;
+ int i;
+ int have_extrabytes = 0;
+
+ nuke(ep, -EPROTO);
+
+ /* read SETUP packet */
+ for (i = 0; i < 2; i++) {
+ if (unlikely(ep_is_empty(ep)))
+ goto stall;
+ u.word[i] = udc_ep_readl(ep, UDCDR);
+ }
+
+ have_extrabytes = !ep_is_empty(ep);
+ while (!ep_is_empty(ep)) {
+ i = udc_ep_readl(ep, UDCDR);
+ ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i);
+ }
+
+ ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+ u.r.bRequestType, u.r.bRequest,
+ le16_to_cpu(u.r.wValue), le16_to_cpu(u.r.wIndex),
+ le16_to_cpu(u.r.wLength));
+ if (unlikely(have_extrabytes))
+ goto stall;
+
+ if (u.r.bRequestType & USB_DIR_IN)
+ set_ep0state(udc, IN_DATA_STAGE);
+ else
+ set_ep0state(udc, OUT_DATA_STAGE);
+
+ /* Tell UDC to enter Data Stage */
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC);
+
+ i = udc->driver->setup(&udc->gadget, &u.r);
+ if (i < 0)
+ goto stall;
+out:
+ return;
+stall:
+ ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
+ udc_ep_readl(ep, UDCCSR), i);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF);
+ set_ep0state(udc, STALL);
+ goto out;
+}
+
+/**
+ * handle_ep0 - Handle control endpoint data transfers
+ * @udc: udc device
+ * @fifo_irq: 1 if triggered by fifo service type irq
+ * @opc_irq: 1 if triggered by output packet complete type irq
+ *
+ * Context : when in_interrupt() or with ep->lock held
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ * Handles states of ep0 automata.
+ *
+ * PXA27x hardware handles several standard usb control requests without
+ * driver notification. The requests fully handled by hardware are :
+ * SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE,
+ * GET_STATUS
+ * The requests handled by hardware, but with irq notification are :
+ * SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE
+ * The remaining standard requests really handled by handle_ep0 are :
+ * GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests.
+ * Requests standardized outside of USB 2.0 chapter 9 are handled more
+ * uniformly, by gadget drivers.
+ *
+ * The control endpoint state machine is _not_ USB spec compliant, it's even
+ * hardly compliant with Intel PXA270 developers guide.
+ * The key points which inferred this state machine are :
+ * - on every setup token, bit UDCCSR0_SA is raised and held until cleared by
+ * software.
+ * - on every OUT packet received, UDCCSR0_OPC is raised and held until
+ * cleared by software.
+ * - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
+ * before reading ep0.
+ * - irq can be called on a "packet complete" event (opc_irq=1), while
+ * UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
+ * from experimentation).
+ * - as UDCCSR0_SA can be activated while in irq handling, and clearing
+ * UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC
+ * => we never actually read the "status stage" packet of an IN data stage
+ * => this is not documented in Intel documentation
+ * - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA
+ * STAGE. The driver add STATUS STAGE to send last zero length packet in
+ * OUT_STATUS_STAGE.
+ * - special attention was needed for IN_STATUS_STAGE. If a packet complete
+ * event is detected, we terminate the status stage without ackowledging the
+ * packet (not to risk to loose a potential SETUP packet)
+ */
+static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
+{
+ u32 udccsr0;
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ struct pxa27x_request *req = NULL;
+ int completed = 0;
+
+ udccsr0 = udc_ep_readl(ep, UDCCSR);
+ ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n",
+ EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR),
+ (fifo_irq << 1 | opc_irq));
+
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+
+ if (udccsr0 & UDCCSR0_SST) {
+ ep_dbg(ep, "clearing stall status\n");
+ nuke(ep, -EPIPE);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_SST);
+ ep0_idle(udc);
+ }
+
+ if (udccsr0 & UDCCSR0_SA) {
+ nuke(ep, 0);
+ set_ep0state(udc, SETUP_STAGE);
+ }
+
+ switch (udc->ep0state) {
+ case WAIT_FOR_SETUP:
+ /*
+ * Hardware bug : beware, we cannot clear OPC, since we would
+ * miss a potential OPC irq for a setup packet.
+ * So, we only do ... nothing, and hope for a next irq with
+ * UDCCSR0_SA set.
+ */
+ break;
+ case SETUP_STAGE:
+ udccsr0 &= UDCCSR0_CTRL_REQ_MASK;
+ if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK))
+ handle_ep0_ctrl_req(udc, req);
+ break;
+ case IN_DATA_STAGE: /* GET_DESCRIPTOR */
+ if (epout_has_pkt(ep))
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+ if (req && !ep_is_full(ep))
+ completed = write_ep0_fifo(ep, req);
+ if (completed)
+ ep0_end_in_req(ep, req);
+ break;
+ case OUT_DATA_STAGE: /* SET_DESCRIPTOR */
+ if (epout_has_pkt(ep) && req)
+ completed = read_ep0_fifo(ep, req);
+ if (completed)
+ ep0_end_out_req(ep, req);
+ break;
+ case STALL:
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FST);
+ break;
+ case IN_STATUS_STAGE:
+ /*
+ * Hardware bug : beware, we cannot clear OPC, since we would
+ * miss a potential PC irq for a setup packet.
+ * So, we only put the ep0 into WAIT_FOR_SETUP state.
+ */
+ if (opc_irq)
+ ep0_idle(udc);
+ break;
+ case OUT_STATUS_STAGE:
+ case WAIT_ACK_SET_CONF_INTERF:
+ ep_warn(ep, "should never get in %s state here!!!\n",
+ EP0_STNAME(ep->dev));
+ ep0_idle(udc);
+ break;
+ }
+}
+
+/**
+ * handle_ep - Handle endpoint data tranfers
+ * @ep: pxa physical endpoint
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ *
+ * Is always called when in_interrupt() or with ep->lock held.
+ */
+static void handle_ep(struct pxa_ep *ep)
+{
+ struct pxa27x_request *req;
+ int completed;
+ u32 udccsr;
+ int is_in = ep->dir_in;
+ int loop = 0;
+
+ do {
+ completed = 0;
+ udccsr = udc_ep_readl(ep, UDCCSR);
+ if (likely(!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct pxa27x_request, queue);
+ else
+ req = NULL;
+
+ ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n",
+ req, udccsr, loop++);
+
+ if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN)))
+ udc_ep_writel(ep, UDCCSR,
+ udccsr & (UDCCSR_SST | UDCCSR_TRN));
+ if (!req)
+ break;
+
+ if (unlikely(is_in)) {
+ if (likely(!ep_is_full(ep)))
+ completed = write_fifo(ep, req);
+ if (completed)
+ ep_end_in_req(ep, req);
+ } else {
+ if (likely(epout_has_pkt(ep)))
+ completed = read_fifo(ep, req);
+ if (completed)
+ ep_end_out_req(ep, req);
+ }
+ } while (completed);
+}
+
+/**
+ * pxa27x_change_configuration - Handle SET_CONF usb request notification
+ * @udc: udc device
+ * @config: usb configuration
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_configuration(struct pxa_udc *udc, int config)
+{
+ struct usb_ctrlrequest req ;
+
+ dev_dbg(udc->dev, "config=%d\n", config);
+
+ udc->config = config;
+ udc->last_interface = 0;
+ udc->last_alternate = 0;
+
+ req.bRequestType = 0;
+ req.bRequest = USB_REQ_SET_CONFIGURATION;
+ req.wValue = config;
+ req.wIndex = 0;
+ req.wLength = 0;
+
+ set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+ udc->driver->setup(&udc->gadget, &req);
+}
+
+/**
+ * pxa27x_change_interface - Handle SET_INTERF usb request notification
+ * @udc: udc device
+ * @iface: interface number
+ * @alt: alternate setting number
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
+{
+ struct usb_ctrlrequest req;
+
+ dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt);
+
+ udc->last_interface = iface;
+ udc->last_alternate = alt;
+
+ req.bRequestType = USB_RECIP_INTERFACE;
+ req.bRequest = USB_REQ_SET_INTERFACE;
+ req.wValue = alt;
+ req.wIndex = iface;
+ req.wLength = 0;
+
+ set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+ udc->driver->setup(&udc->gadget, &req);
+}
+
+/*
+ * irq_handle_data - Handle data transfer
+ * @irq: irq IRQ number
+ * @udc: dev pxa_udc device structure
+ *
+ * Called from irq handler, transferts data to or from endpoint to queue
+ */
+static void irq_handle_data(int irq, struct pxa_udc *udc)
+{
+ int i;
+ struct pxa_ep *ep;
+ u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK;
+ u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK;
+
+ if (udcisr0 & UDCISR_INT_MASK) {
+ udc->pxa_ep[0].stats.irqs++;
+ udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK));
+ handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR),
+ !!(udcisr0 & UDCICR_PKTCOMPL));
+ }
+
+ udcisr0 >>= 2;
+ for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) {
+ if (!(udcisr0 & UDCISR_INT_MASK))
+ continue;
+
+ udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
+
+ for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
+ udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK));
+ if (!(udcisr1 & UDCISR_INT_MASK))
+ continue;
+
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
+
+}
+
+/**
+ * irq_udc_suspend - Handle IRQ "UDC Suspend"
+ * @udc: udc device
+ */
+static void irq_udc_suspend(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCISR1, UDCISR1_IRSU);
+ udc->stats.irqs_suspend++;
+
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+ ep0_idle(udc);
+}
+
+/**
+ * irq_udc_resume - Handle IRQ "UDC Resume"
+ * @udc: udc device
+ */
+static void irq_udc_resume(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCISR1, UDCISR1_IRRU);
+ udc->stats.irqs_resume++;
+
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+/**
+ * irq_udc_reconfig - Handle IRQ "UDC Change Configuration"
+ * @udc: udc device
+ */
+static void irq_udc_reconfig(struct pxa_udc *udc)
+{
+ unsigned config, interface, alternate, config_change;
+ u32 udccr = udc_readl(udc, UDCCR);
+
+ udc_writel(udc, UDCISR1, UDCISR1_IRCC);
+ udc->stats.irqs_reconfig++;
+
+ config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S;
+ config_change = (config != udc->config);
+ pxa27x_change_configuration(udc, config);
+
+ interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S;
+ alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S;
+ pxa27x_change_interface(udc, interface, alternate);
+
+ if (config_change)
+ update_pxa_ep_matches(udc);
+ udc_set_mask_UDCCR(udc, UDCCR_SMAC);
+}
+
+/**
+ * irq_udc_reset - Handle IRQ "UDC Reset"
+ * @udc: udc device
+ */
+static void irq_udc_reset(struct pxa_udc *udc)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+
+ dev_info(udc->dev, "USB reset\n");
+ udc_writel(udc, UDCISR1, UDCISR1_IRRS);
+ udc->stats.irqs_reset++;
+
+ if ((udccr & UDCCR_UDA) == 0) {
+ dev_dbg(udc->dev, "USB reset start\n");
+ stop_activity(udc, udc->driver);
+ }
+ udc->gadget.speed = USB_SPEED_FULL;
+ memset(&udc->stats, 0, sizeof udc->stats);
+
+ nuke(ep, -EPROTO);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC);
+ ep0_idle(udc);
+}
+
+/**
+ * pxa_udc_irq - Main irq handler
+ * @irq: irq number
+ * @_dev: udc device
+ *
+ * Handles all udc interrupts
+ */
+static irqreturn_t pxa_udc_irq(int irq, void *_dev)
+{
+ struct pxa_udc *udc = _dev;
+ u32 udcisr0 = udc_readl(udc, UDCISR0);
+ u32 udcisr1 = udc_readl(udc, UDCISR1);
+ u32 udccr = udc_readl(udc, UDCCR);
+ u32 udcisr1_spec;
+
+ dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, "
+ "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr);
+
+ udcisr1_spec = udcisr1 & 0xf8000000;
+ if (unlikely(udcisr1_spec & UDCISR1_IRSU))
+ irq_udc_suspend(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRRU))
+ irq_udc_resume(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRCC))
+ irq_udc_reconfig(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRRS))
+ irq_udc_reset(udc);
+
+ if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK))
+ irq_handle_data(irq, udc);
+
+ return IRQ_HANDLED;
+}
+
+static struct pxa_udc memory = {
+ .gadget = {
+ .ops = &pxa_udc_ops,
+ .ep0 = &memory.udc_usb_ep[0].usb_ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+
+ .udc_usb_ep = {
+ USB_EP_CTRL,
+ USB_EP_OUT_BULK(1),
+ USB_EP_IN_BULK(2),
+ USB_EP_IN_ISO(3),
+ USB_EP_OUT_ISO(4),
+ USB_EP_IN_INT(5),
+ },
+
+ .pxa_ep = {
+ PXA_EP_CTRL,
+ /* Endpoints for gadget zero */
+ PXA_EP_OUT_BULK(1, 1, 3, 0, 0),
+ PXA_EP_IN_BULK(2, 2, 3, 0, 0),
+ /* Endpoints for ether gadget, file storage gadget */
+ PXA_EP_OUT_BULK(3, 1, 1, 0, 0),
+ PXA_EP_IN_BULK(4, 2, 1, 0, 0),
+ PXA_EP_IN_ISO(5, 3, 1, 0, 0),
+ PXA_EP_OUT_ISO(6, 4, 1, 0, 0),
+ PXA_EP_IN_INT(7, 5, 1, 0, 0),
+ /* Endpoints for RNDIS, serial */
+ PXA_EP_OUT_BULK(8, 1, 2, 0, 0),
+ PXA_EP_IN_BULK(9, 2, 2, 0, 0),
+ PXA_EP_IN_INT(10, 5, 2, 0, 0),
+ /*
+ * All the following endpoints are only for completion. They
+ * won't never work, as multiple interfaces are really broken on
+ * the pxa.
+ */
+ PXA_EP_OUT_BULK(11, 1, 2, 1, 0),
+ PXA_EP_IN_BULK(12, 2, 2, 1, 0),
+ /* Endpoint for CDC Ether */
+ PXA_EP_OUT_BULK(13, 1, 1, 1, 1),
+ PXA_EP_IN_BULK(14, 2, 1, 1, 1),
+ }
+};
+
+/**
+ * pxa_udc_probe - probes the udc device
+ * @_dev: platform device
+ *
+ * Perform basic init : allocates udc clock, creates sysfs files, requests
+ * irq.
+ */
+static int __init pxa_udc_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct pxa_udc *udc = &memory;
+ int retval;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+ udc->irq = platform_get_irq(pdev, 0);
+ if (udc->irq < 0)
+ return udc->irq;
+
+ udc->dev = &pdev->dev;
+ udc->mach = pdev->dev.platform_data;
+
+ udc->clk = clk_get(&pdev->dev, "UDCCLK");
+ if (IS_ERR(udc->clk)) {
+ retval = PTR_ERR(udc->clk);
+ goto err_clk;
+ }
+
+ retval = -ENOMEM;
+ udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!udc->regs) {
+ dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
+ goto err_map;
+ }
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = NULL;
+
+ the_controller = udc;
+ platform_set_drvdata(pdev, udc);
+ udc_init_data(udc);
+ pxa_eps_setup(udc);
+
+ /* irq setup after old hardware state is cleaned up */
+ retval = request_irq(udc->irq, pxa_udc_irq,
+ IRQF_SHARED, driver_name, udc);
+ if (retval != 0) {
+ dev_err(udc->dev, "%s: can't get irq %i, err %d\n",
+ driver_name, IRQ_USB, retval);
+ goto err_irq;
+ }
+
+ pxa_init_debugfs(udc);
+ return 0;
+err_irq:
+ iounmap(udc->regs);
+err_map:
+ clk_put(udc->clk);
+ udc->clk = NULL;
+err_clk:
+ return retval;
+}
+
+/**
+ * pxa_udc_remove - removes the udc device driver
+ * @_dev: platform device
+ */
+static int __exit pxa_udc_remove(struct platform_device *_dev)
+{
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+ usb_gadget_unregister_driver(udc->driver);
+ free_irq(udc->irq, udc);
+ pxa_cleanup_debugfs(udc);
+
+ platform_set_drvdata(_dev, NULL);
+ the_controller = NULL;
+ clk_put(udc->clk);
+
+ return 0;
+}
+
+static void pxa_udc_shutdown(struct platform_device *_dev)
+{
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+ if (udc_readl(udc, UDCCR) & UDCCR_UDE)
+ udc_disable(udc);
+}
+
+#ifdef CONFIG_PM
+/**
+ * pxa_udc_suspend - Suspend udc device
+ * @_dev: platform device
+ * @state: suspend state
+ *
+ * Suspends udc : saves configuration registers (UDCCR*), then disables the udc
+ * device.
+ */
+static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
+{
+ int i;
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+ struct pxa_ep *ep;
+
+ ep = &udc->pxa_ep[0];
+ udc->udccsr0 = udc_ep_readl(ep, UDCCSR);
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ ep->udccsr_value = udc_ep_readl(ep, UDCCSR);
+ ep->udccr_value = udc_ep_readl(ep, UDCCR);
+ ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+ ep->udccsr_value, ep->udccr_value);
+ }
+
+ udc_disable(udc);
+
+ return 0;
+}
+
+/**
+ * pxa_udc_resume - Resume udc device
+ * @_dev: platform device
+ *
+ * Resumes udc : restores configuration registers (UDCCR*), then enables the udc
+ * device.
+ */
+static int pxa_udc_resume(struct platform_device *_dev)
+{
+ int i;
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+ struct pxa_ep *ep;
+
+ ep = &udc->pxa_ep[0];
+ udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME));
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ udc_ep_writel(ep, UDCCSR, ep->udccsr_value);
+ udc_ep_writel(ep, UDCCR, ep->udccr_value);
+ ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+ ep->udccsr_value, ep->udccr_value);
+ }
+
+ udc_enable(udc);
+ /*
+ * We do not handle OTG yet.
+ *
+ * OTGPH bit is set when sleep mode is entered.
+ * it indicates that OTG pad is retaining its state.
+ * Upon exit from sleep mode and before clearing OTGPH,
+ * Software must configure the USB OTG pad, UDC, and UHC
+ * to the state they were in before entering sleep mode.
+ */
+ PSSR |= PSSR_OTGPH;
+
+ return 0;
+}
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:pxa2xx-udc");
+
+static struct platform_driver udc_driver = {
+ .driver = {
+ .name = "pxa2xx-udc",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(pxa_udc_remove),
+ .shutdown = pxa_udc_shutdown,
+#ifdef CONFIG_PM
+ .suspend = pxa_udc_suspend,
+ .resume = pxa_udc_resume
+#endif
+};
+
+static int __init udc_init(void)
+{
+ if (!cpu_is_pxa27x())
+ return -ENODEV;
+
+ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
+ return platform_driver_probe(&udc_driver, pxa_udc_probe);
+}
+module_init(udc_init);
+
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
new file mode 100644
index 000000000000..97453db924ff
--- /dev/null
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -0,0 +1,495 @@
+/*
+ * linux/drivers/usb/gadget/pxa27x_udc.h
+ * Intel PXA27x on-chip full speed USB device controller
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 __LINUX_USB_GADGET_PXA27X_H
+#define __LINUX_USB_GADGET_PXA27X_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+/*
+ * Register definitions
+ */
+/* Offsets */
+#define UDCCR 0x0000 /* UDC Control Register */
+#define UDCICR0 0x0004 /* UDC Interrupt Control Register0 */
+#define UDCICR1 0x0008 /* UDC Interrupt Control Register1 */
+#define UDCISR0 0x000C /* UDC Interrupt Status Register 0 */
+#define UDCISR1 0x0010 /* UDC Interrupt Status Register 1 */
+#define UDCFNR 0x0014 /* UDC Frame Number Register */
+#define UDCOTGICR 0x0018 /* UDC On-The-Go interrupt control */
+#define UP2OCR 0x0020 /* USB Port 2 Output Control register */
+#define UP3OCR 0x0024 /* USB Port 3 Output Control register */
+#define UDCCSRn(x) (0x0100 + ((x)<<2)) /* UDC Control/Status register */
+#define UDCBCRn(x) (0x0200 + ((x)<<2)) /* UDC Byte Count Register */
+#define UDCDRn(x) (0x0300 + ((x)<<2)) /* UDC Data Register */
+#define UDCCRn(x) (0x0400 + ((x)<<2)) /* UDC Control Register */
+
+#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */
+#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation
+ Protocol Port Support */
+#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol
+ Support */
+#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol
+ Enable */
+#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */
+#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */
+#define UDCCR_ACN_S 11
+#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */
+#define UDCCR_AIN_S 8
+#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface
+ Setting Number */
+#define UDCCR_AAISN_S 5
+#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active
+ Configuration */
+#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration
+ Error */
+#define UDCCR_UDR (1 << 2) /* UDC Resume */
+#define UDCCR_UDA (1 << 1) /* UDC Active */
+#define UDCCR_UDE (1 << 0) /* UDC Enable */
+
+#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */
+#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */
+#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */
+#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */
+#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */
+#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */
+#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */
+#define UDCICR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */
+#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */
+#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */
+#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */
+#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */
+#define UDCISR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */
+#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt
+ Rising Edge Interrupt Enable */
+#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt
+ Falling Edge Interrupt Enable */
+#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising
+ Edge Interrupt Enable */
+#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling
+ Edge Interrupt Enable */
+#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge
+ Interrupt Enable */
+
+/* Host Port 2 field bits */
+#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */
+#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */
+ /* Transceiver enablers */
+#define UP2OCR_DPPDE (1 << 2) /* D+ Pull Down Enable */
+#define UP2OCR_DMPDE (1 << 3) /* D- Pull Down Enable */
+#define UP2OCR_DPPUE (1 << 4) /* D+ Pull Up Enable */
+#define UP2OCR_DMPUE (1 << 5) /* D- Pull Up Enable */
+#define UP2OCR_DPPUBE (1 << 6) /* D+ Pull Up Bypass Enable */
+#define UP2OCR_DMPUBE (1 << 7) /* D- Pull Up Bypass Enable */
+#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */
+#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */
+#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */
+#define UP2OCR_HXS (1 << 16) /* Transceiver Output Select */
+#define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */
+#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */
+
+#define UDCCSR0_SA (1 << 7) /* Setup Active */
+#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */
+#define UDCCSR0_FST (1 << 5) /* Force Stall */
+#define UDCCSR0_SST (1 << 4) /* Sent Stall */
+#define UDCCSR0_DME (1 << 3) /* DMA Enable */
+#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */
+#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */
+#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */
+
+#define UDCCSR_DPE (1 << 9) /* Data Packet Error */
+#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */
+#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */
+#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */
+#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */
+#define UDCCSR_FST (1 << 5) /* Force STALL */
+#define UDCCSR_SST (1 << 4) /* Sent STALL */
+#define UDCCSR_DME (1 << 3) /* DMA Enable */
+#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */
+#define UDCCSR_PC (1 << 1) /* Packet Complete */
+#define UDCCSR_FS (1 << 0) /* FIFO needs service */
+
+#define UDCCONR_CN (0x03 << 25) /* Configuration Number */
+#define UDCCONR_CN_S 25
+#define UDCCONR_IN (0x07 << 22) /* Interface Number */
+#define UDCCONR_IN_S 22
+#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */
+#define UDCCONR_AISN_S 19
+#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */
+#define UDCCONR_EN_S 15
+#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */
+#define UDCCONR_ET_S 13
+#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */
+#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */
+#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */
+#define UDCCONR_ET_NU (0x00 << 13) /* Not used */
+#define UDCCONR_ED (1 << 12) /* Endpoint Direction */
+#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */
+#define UDCCONR_MPS_S 2
+#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */
+#define UDCCONR_EE (1 << 0) /* Endpoint Enable */
+
+#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE)
+#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST)
+#define UDC_FNR_MASK (0x7ff)
+#define UDC_BCR_MASK (0x3ff)
+
+/*
+ * UDCCR = UDC Endpoint Configuration Registers
+ * UDCCSR = UDC Control/Status Register for this EP
+ * UDCBCR = UDC Byte Count Remaining (contents of OUT fifo)
+ * UDCDR = UDC Endpoint Data Register (the fifo)
+ */
+#define ofs_UDCCR(ep) (UDCCRn(ep->idx))
+#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx))
+#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx))
+#define ofs_UDCDR(ep) (UDCDRn(ep->idx))
+
+/* Register access macros */
+#define udc_ep_readl(ep, reg) \
+ __raw_readl((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writel(ep, reg, value) \
+ __raw_writel((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_ep_readb(ep, reg) \
+ __raw_readb((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writeb(ep, reg, value) \
+ __raw_writeb((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_readl(dev, reg) \
+ __raw_readl((dev)->regs + (reg))
+#define udc_writel(udc, reg, value) \
+ __raw_writel((value), (udc)->regs + (reg))
+
+#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME)
+#define UDCCISR0_EP_MASK ~0
+#define UDCCISR1_EP_MASK 0xffff
+#define UDCCSR0_CTRL_REQ_MASK (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)
+
+#define EPIDX(ep) (ep->idx)
+#define EPADDR(ep) (ep->addr)
+#define EPXFERTYPE(ep) (ep->type)
+#define EPNAME(ep) (ep->name)
+#define is_ep0(ep) (!ep->idx)
+#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC)
+
+/*
+ * Endpoint definitions
+ *
+ * Once enabled, pxa endpoint configuration is freezed, and cannot change
+ * unless a reset happens or the udc is disabled.
+ * Therefore, we must define all pxa potential endpoint definitions needed for
+ * all gadget and set them up before the udc is enabled.
+ *
+ * As the architecture chosen is fully static, meaning the pxa endpoint
+ * configurations are set up once and for all, we must provide a way to match
+ * one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget
+ * layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt)
+ * criteria, while the pxa architecture requires that.
+ *
+ * The solution is to define several pxa endpoints matching one usb_ep. Ex:
+ * - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when
+ * the udc talks on (config=3, interface=0, alt=0)
+ * - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when
+ * the udc talks on (config=3, interface=0, alt=1)
+ * - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when
+ * the udc talks on (config=2, interface=0, alt=0)
+ *
+ * We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...)
+ */
+
+/*
+ * Endpoint definition helpers
+ */
+#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \
+{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \
+ .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \
+ .bmAttributes = type, \
+ .wMaxPacketSize = maxpkt, }, \
+ .dev = &memory \
+}
+#define USB_EP_BULK(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE)
+#define USB_EP_ISO(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE)
+#define USB_EP_INT(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE)
+#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1)
+#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0)
+#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1)
+#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0)
+#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1)
+#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE)
+
+#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \
+{ \
+ .dev = &memory, \
+ .name = "ep" #_idx, \
+ .idx = _idx, .enabled = 0, \
+ .dir_in = dir, .addr = _addr, \
+ .config = _config, .interface = iface, .alternate = altset, \
+ .type = _type, .fifo_size = maxpkt, \
+}
+#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_IN_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 0, c, f, a)
+#define PXA_EP_IN_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 0, c, f, a)
+#define PXA_EP_IN_INT(i, adr, c, f, a) PXA_EP_INT(i, adr, 1, c, f, a)
+#define PXA_EP_CTRL PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0)
+
+struct pxa27x_udc;
+
+struct stats {
+ unsigned long in_ops;
+ unsigned long out_ops;
+ unsigned long in_bytes;
+ unsigned long out_bytes;
+ unsigned long irqs;
+};
+
+/**
+ * struct udc_usb_ep - container of each usb_ep structure
+ * @usb_ep: usb endpoint
+ * @desc: usb descriptor, especially type and address
+ * @dev: udc managing this endpoint
+ * @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call)
+ */
+struct udc_usb_ep {
+ struct usb_ep usb_ep;
+ struct usb_endpoint_descriptor desc;
+ struct pxa_udc *dev;
+ struct pxa_ep *pxa_ep;
+};
+
+/**
+ * struct pxa_ep - pxa endpoint
+ * @dev: udc device
+ * @queue: requests queue
+ * @lock: lock to pxa_ep data (queues and stats)
+ * @enabled: true when endpoint enabled (not stopped by gadget layer)
+ * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
+ * @name: endpoint name (for trace/debug purpose)
+ * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
+ * @addr: usb endpoint number
+ * @config: configuration in which this endpoint is active
+ * @interface: interface in which this endpoint is active
+ * @alternate: altsetting in which this endpoitn is active
+ * @fifo_size: max packet size in the endpoint fifo
+ * @type: endpoint type (bulk, iso, int, ...)
+ * @udccsr_value: save register of UDCCSR0 for suspend/resume
+ * @udccr_value: save register of UDCCR for suspend/resume
+ * @stats: endpoint statistics
+ *
+ * The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned
+ * (cares about config/interface/altsetting, thus placing needless limits on
+ * device capability) and full of implementation bugs forcing it to be set up
+ * for use more or less like a pxa255.
+ *
+ * As we define the pxa_ep statically, we must guess all needed pxa_ep for all
+ * gadget which may work with this udc driver.
+ */
+struct pxa_ep {
+ struct pxa_udc *dev;
+
+ struct list_head queue;
+ spinlock_t lock; /* Protects this structure */
+ /* (queues, stats) */
+ unsigned enabled:1;
+
+ unsigned idx:5;
+ char *name;
+
+ /*
+ * Specific pxa endpoint data, needed for hardware initialization
+ */
+ unsigned dir_in:1;
+ unsigned addr:3;
+ unsigned config:2;
+ unsigned interface:3;
+ unsigned alternate:3;
+ unsigned fifo_size;
+ unsigned type;
+
+#ifdef CONFIG_PM
+ u32 udccsr_value;
+ u32 udccr_value;
+#endif
+ struct stats stats;
+};
+
+/**
+ * struct pxa27x_request - container of each usb_request structure
+ * @req: usb request
+ * @udc_usb_ep: usb endpoint the request was submitted on
+ * @in_use: sanity check if request already queued on an pxa_ep
+ * @queue: linked list of requests, linked on pxa_ep->queue
+ */
+struct pxa27x_request {
+ struct usb_request req;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned in_use:1;
+ struct list_head queue;
+};
+
+enum ep0_state {
+ WAIT_FOR_SETUP,
+ SETUP_STAGE,
+ IN_DATA_STAGE,
+ OUT_DATA_STAGE,
+ IN_STATUS_STAGE,
+ OUT_STATUS_STAGE,
+ STALL,
+ WAIT_ACK_SET_CONF_INTERF
+};
+
+static char *ep0_state_name[] = {
+ "WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE",
+ "IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL",
+ "WAIT_ACK_SET_CONF_INTERF"
+};
+#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state]
+
+#define EP0_FIFO_SIZE 16U
+#define BULK_FIFO_SIZE 64U
+#define ISO_FIFO_SIZE 256U
+#define INT_FIFO_SIZE 16U
+
+struct udc_stats {
+ unsigned long irqs_reset;
+ unsigned long irqs_suspend;
+ unsigned long irqs_resume;
+ unsigned long irqs_reconfig;
+};
+
+#define NR_USB_ENDPOINTS (1 + 5) /* ep0 + ep1in-bulk + .. + ep3in-iso */
+#define NR_PXA_ENDPOINTS (1 + 14) /* ep0 + epA + epB + .. + epX */
+
+/**
+ * struct pxa_udc - udc structure
+ * @regs: mapped IO space
+ * @irq: udc irq
+ * @clk: udc clock
+ * @usb_gadget: udc gadget structure
+ * @driver: bound gadget (zero, g_ether, g_file_storage, ...)
+ * @dev: device
+ * @mach: machine info, used to activate specific GPIO
+ * @ep0state: control endpoint state machine state
+ * @stats: statistics on udc usage
+ * @udc_usb_ep: array of usb endpoints offered by the gadget
+ * @pxa_ep: array of pxa available endpoints
+ * @config: UDC active configuration
+ * @last_interface: UDC interface of the last SET_INTERFACE host request
+ * @last_alternate: UDC altsetting of the last SET_INTERFACE host request
+ * @udccsr0: save of udccsr0 in case of suspend
+ * @debugfs_root: root entry of debug filesystem
+ * @debugfs_state: debugfs entry for "udcstate"
+ * @debugfs_queues: debugfs entry for "queues"
+ * @debugfs_eps: debugfs entry for "epstate"
+ */
+struct pxa_udc {
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ struct pxa2xx_udc_mach_info *mach;
+
+ enum ep0_state ep0state;
+ struct udc_stats stats;
+
+ struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS];
+ struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS];
+
+ unsigned config:2;
+ unsigned last_interface:3;
+ unsigned last_alternate:3;
+
+#ifdef CONFIG_PM
+ unsigned udccsr0;
+#endif
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_state;
+ struct dentry *debugfs_queues;
+ struct dentry *debugfs_eps;
+#endif
+};
+
+static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct pxa_udc, gadget);
+}
+
+/*
+ * Debugging/message support
+ */
+#define ep_dbg(ep, fmt, arg...) \
+ dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_vdbg(ep, fmt, arg...) \
+ dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_err(ep, fmt, arg...) \
+ dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_info(ep, fmt, arg...) \
+ dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_warn(ep, fmt, arg...) \
+ dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
+
+/*
+ * Cannot include pxa-regs.h, as register names are similar.
+ * So PSSR is redefined here. This should be removed once UDC registers will
+ * be gone from pxa-regs.h.
+ */
+#define PSSR __REG(0x40F00004) /* Power Manager Sleep Status */
+#define PSSR_OTGPH (1 << 6) /* OTG Peripheral Hold */
+
+#endif /* __LINUX_USB_GADGET_PXA27X_H */
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index bd58dd504f6f..d0677f5d3cd5 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -183,14 +183,10 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
DBG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DBG("%03d: %08x %08x %08x %08x\n", i,
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 4])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 8])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 12])));
+ get_unaligned_le32(&buf[i]),
+ get_unaligned_le32(&buf[i + 4]),
+ get_unaligned_le32(&buf[i + 8]),
+ get_unaligned_le32(&buf[i + 12]));
}
}
@@ -666,7 +662,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_PNP_QUERY_POWER:
DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
- le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
+ get_unaligned_le32(buf) - 1);
/* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
*/
@@ -705,14 +701,10 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
DBG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DBG("%03d: %08x %08x %08x %08x\n", i,
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 4])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 8])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 12])));
+ get_unaligned_le32(&buf[i]),
+ get_unaligned_le32(&buf[i + 4]),
+ get_unaligned_le32(&buf[i + 8]),
+ get_unaligned_le32(&buf[i + 12]));
}
}
@@ -726,8 +718,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
* PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST
*/
- *params->filter = (u16) le32_to_cpu(get_unaligned(
- (__le32 *)buf));
+ *params->filter = (u16)get_unaligned_le32(buf);
DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__func__, *params->filter);
@@ -777,7 +768,7 @@ update_linkstate:
* resuming, Windows forces a reset, and then SET_POWER D0.
* FIXME ... then things go batty; Windows wedges itself.
*/
- i = le32_to_cpu(get_unaligned((__le32 *)buf));
+ i = get_unaligned_le32(buf);
DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
switch (i) {
case NdisDeviceStateD0:
@@ -1064,8 +1055,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
return -ENOMEM;
tmp = (__le32 *) buf;
- MsgType = le32_to_cpu(get_unaligned(tmp++));
- MsgLength = le32_to_cpu(get_unaligned(tmp++));
+ MsgType = get_unaligned_le32(tmp++);
+ MsgLength = get_unaligned_le32(tmp++);
if (configNr >= RNDIS_MAX_CONFIGS)
return -ENOTSUPP;
@@ -1296,10 +1287,9 @@ int rndis_rm_hdr(struct sk_buff *skb)
tmp++;
/* DataOffset, DataLength */
- if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
- + 8 /* offset of DataOffset */))
+ if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8))
return -EOVERFLOW;
- skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
+ skb_trim(skb, get_unaligned_le32(tmp++));
return 0;
}
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 433b3f44f42e..fa019fa73334 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -14,7 +14,6 @@
* This software is distributed under the terms of the GNU General
* Public License ("GPL") as published by the Free Software Foundation,
* either version 2 of that License or (at your option) any later version.
- *
*/
#include <linux/kernel.h>
@@ -33,7 +32,7 @@
/* Defines */
#define GS_VERSION_STR "v2.2"
-#define GS_VERSION_NUM 0x0202
+#define GS_VERSION_NUM 0x2200
#define GS_LONG_NAME "Gadget Serial"
#define GS_SHORT_NAME "g_serial"
@@ -41,7 +40,11 @@
#define GS_MAJOR 127
#define GS_MINOR_START 0
-#define GS_NUM_PORTS 16
+/* REVISIT only one port is supported for now;
+ * see gs_{send,recv}_packet() ... no multiplexing,
+ * and no support for multiple ACM devices.
+ */
+#define GS_NUM_PORTS 1
#define GS_NUM_CONFIGS 1
#define GS_NO_CONFIG_ID 0
@@ -65,6 +68,9 @@
#define GS_DEFAULT_USE_ACM 0
+/* 9600-8-N-1 ... matches init_termios.c_cflag and defaults
+ * expected by "usbser.sys" on MS-Windows.
+ */
#define GS_DEFAULT_DTE_RATE 9600
#define GS_DEFAULT_DATA_BITS 8
#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
@@ -107,10 +113,6 @@ static int debug = 1;
#define GS_NOTIFY_MAXPACKET 8
-/* Structures */
-
-struct gs_dev;
-
/* circular buffer */
struct gs_buf {
unsigned int buf_size;
@@ -119,12 +121,6 @@ struct gs_buf {
char *buf_put;
};
-/* list of requests */
-struct gs_req_entry {
- struct list_head re_entry;
- struct usb_request *re_req;
-};
-
/* the port structure holds info for each port, one for each minor number */
struct gs_port {
struct gs_dev *port_dev; /* pointer to device struct */
@@ -135,7 +131,10 @@ struct gs_port {
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
struct gs_buf *port_write_buf;
- struct usb_cdc_line_coding port_line_coding;
+ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
+ u16 port_handshake_bits;
+#define RS232_RTS (1 << 1)
+#define RS232_DTE (1 << 0)
};
/* the device structure holds info for the USB device */
@@ -161,26 +160,7 @@ struct gs_dev {
/* Functions */
-/* module */
-static int __init gs_module_init(void);
-static void __exit gs_module_exit(void);
-
-/* tty driver */
-static int gs_open(struct tty_struct *tty, struct file *file);
-static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty,
- const unsigned char *buf, int count);
-static void gs_put_char(struct tty_struct *tty, unsigned char ch);
-static void gs_flush_chars(struct tty_struct *tty);
-static int gs_write_room(struct tty_struct *tty);
-static int gs_chars_in_buffer(struct tty_struct *tty);
-static void gs_throttle(struct tty_struct * tty);
-static void gs_unthrottle(struct tty_struct * tty);
-static void gs_break(struct tty_struct *tty, int break_state);
-static int gs_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
-static void gs_set_termios(struct tty_struct *tty, struct ktermios *old);
-
+/* tty driver internals */
static int gs_send(struct gs_dev *dev);
static int gs_send_packet(struct gs_dev *dev, char *packet,
unsigned int size);
@@ -189,17 +169,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet,
static void gs_read_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_write_complete(struct usb_ep *ep, struct usb_request *req);
-/* gadget driver */
-static int gs_bind(struct usb_gadget *gadget);
-static void gs_unbind(struct usb_gadget *gadget);
-static int gs_setup(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl);
-static int gs_setup_standard(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl);
-static int gs_setup_class(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl);
-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
-static void gs_disconnect(struct usb_gadget *gadget);
+/* gadget driver internals */
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
@@ -209,10 +179,6 @@ static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
gfp_t kmalloc_flags);
static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
-static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
- gfp_t kmalloc_flags);
-static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
-
static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags);
static void gs_free_ports(struct gs_dev *dev);
@@ -227,62 +193,15 @@ static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf,
static unsigned int gs_buf_get(struct gs_buf *gb, char *buf,
unsigned int count);
-/* external functions */
-extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);
-
/* Globals */
static struct gs_dev *gs_device;
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
-static const char *EP_NOTIFY_NAME;
-
static struct mutex gs_open_close_lock[GS_NUM_PORTS];
-static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
-static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
-
-static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
-
-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
-
-
-/* tty driver struct */
-static const struct tty_operations gs_tty_ops = {
- .open = gs_open,
- .close = gs_close,
- .write = gs_write,
- .put_char = gs_put_char,
- .flush_chars = gs_flush_chars,
- .write_room = gs_write_room,
- .ioctl = gs_ioctl,
- .set_termios = gs_set_termios,
- .throttle = gs_throttle,
- .unthrottle = gs_unthrottle,
- .break_ctl = gs_break,
- .chars_in_buffer = gs_chars_in_buffer,
-};
-static struct tty_driver *gs_tty_driver;
-
-/* gadget driver struct */
-static struct usb_gadget_driver gs_gadget_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- .speed = USB_SPEED_HIGH,
-#else
- .speed = USB_SPEED_FULL,
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
- .function = GS_LONG_NAME,
- .bind = gs_bind,
- .unbind = gs_unbind,
- .setup = gs_setup,
- .disconnect = gs_disconnect,
- .driver = {
- .name = GS_SHORT_NAME,
- },
-};
+/*-------------------------------------------------------------------------*/
/* USB descriptors */
@@ -299,7 +218,6 @@ static char manufacturer[50];
static struct usb_string gs_strings[] = {
{ GS_MANUFACTURER_STR_ID, manufacturer },
{ GS_PRODUCT_STR_ID, GS_LONG_NAME },
- { GS_SERIAL_STR_ID, "0" },
{ GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
{ GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
{ GS_CONTROL_STR_ID, "Gadget Serial Control" },
@@ -322,7 +240,6 @@ static struct usb_device_descriptor gs_device_desc = {
.idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID),
.iManufacturer = GS_MANUFACTURER_STR_ID,
.iProduct = GS_PRODUCT_STR_ID,
- .iSerialNumber = GS_SERIAL_STR_ID,
.bNumConfigurations = GS_NUM_CONFIGS,
};
@@ -359,7 +276,7 @@ static const struct usb_interface_descriptor gs_bulk_interface_desc = {
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = GS_BULK_INTERFACE_ID,
.bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = GS_DATA_STR_ID,
@@ -406,7 +323,7 @@ static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = 0,
+ .bmCapabilities = (1 << 1),
};
static const struct usb_cdc_union_desc gs_union_desc = {
@@ -516,6 +433,8 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
};
+/*-------------------------------------------------------------------------*/
+
/* Module */
MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers");
@@ -526,84 +445,23 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
+static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
module_param(read_q_size, uint, S_IRUGO);
MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
+static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
module_param(write_q_size, uint, S_IRUGO);
MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
+static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
module_param(write_buf_size, uint, S_IRUGO);
MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");
+static unsigned int use_acm = GS_DEFAULT_USE_ACM;
module_param(use_acm, uint, S_IRUGO);
MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
-module_init(gs_module_init);
-module_exit(gs_module_exit);
-
-/*
-* gs_module_init
-*
-* Register as a USB gadget driver and a tty driver.
-*/
-static int __init gs_module_init(void)
-{
- int i;
- int retval;
-
- retval = usb_gadget_register_driver(&gs_gadget_driver);
- if (retval) {
- pr_err("gs_module_init: cannot register gadget driver, "
- "ret=%d\n", retval);
- return retval;
- }
-
- gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
- if (!gs_tty_driver)
- return -ENOMEM;
- gs_tty_driver->owner = THIS_MODULE;
- gs_tty_driver->driver_name = GS_SHORT_NAME;
- gs_tty_driver->name = "ttygs";
- gs_tty_driver->major = GS_MAJOR;
- gs_tty_driver->minor_start = GS_MINOR_START;
- gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- gs_tty_driver->init_termios = tty_std_termios;
- gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- tty_set_operations(gs_tty_driver, &gs_tty_ops);
-
- for (i=0; i < GS_NUM_PORTS; i++)
- mutex_init(&gs_open_close_lock[i]);
-
- retval = tty_register_driver(gs_tty_driver);
- if (retval) {
- usb_gadget_unregister_driver(&gs_gadget_driver);
- put_tty_driver(gs_tty_driver);
- pr_err("gs_module_init: cannot register tty driver, "
- "ret=%d\n", retval);
- return retval;
- }
-
- pr_info("gs_module_init: %s %s loaded\n",
- GS_LONG_NAME, GS_VERSION_STR);
- return 0;
-}
-
-/*
-* gs_module_exit
-*
-* Unregister as a tty driver and a USB gadget driver.
-*/
-static void __exit gs_module_exit(void)
-{
- tty_unregister_driver(gs_tty_driver);
- put_tty_driver(gs_tty_driver);
- usb_gadget_unregister_driver(&gs_gadget_driver);
-
- pr_info("gs_module_exit: %s %s unloaded\n",
- GS_LONG_NAME, GS_VERSION_STR);
-}
+/*-------------------------------------------------------------------------*/
/* TTY Driver */
@@ -748,15 +606,15 @@ exit_unlock_dev:
* gs_close
*/
-#define GS_WRITE_FINISHED_EVENT_SAFELY(p) \
-({ \
- int cond; \
- \
- spin_lock_irq(&(p)->port_lock); \
- cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf); \
- spin_unlock_irq(&(p)->port_lock); \
- cond; \
-})
+static int gs_write_finished_event_safely(struct gs_port *p)
+{
+ int cond;
+
+ spin_lock_irq(&(p)->port_lock);
+ cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf);
+ spin_unlock_irq(&(p)->port_lock);
+ return cond;
+}
static void gs_close(struct tty_struct *tty, struct file *file)
{
@@ -802,7 +660,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
if (gs_buf_data_avail(port->port_write_buf) > 0) {
spin_unlock_irq(&port->port_lock);
wait_event_interruptible_timeout(port->port_write_wait,
- GS_WRITE_FINISHED_EVENT_SAFELY(port),
+ gs_write_finished_event_safely(port),
GS_CLOSE_TIMEOUT * HZ);
spin_lock_irq(&port->port_lock);
}
@@ -883,14 +741,15 @@ exit:
/*
* gs_put_char
*/
-static void gs_put_char(struct tty_struct *tty, unsigned char ch)
+static int gs_put_char(struct tty_struct *tty, unsigned char ch)
{
unsigned long flags;
struct gs_port *port = tty->driver_data;
+ int ret = 0;
if (port == NULL) {
pr_err("gs_put_char: NULL port pointer\n");
- return;
+ return 0;
}
gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
@@ -910,10 +769,11 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
goto exit;
}
- gs_buf_put(port->port_write_buf, &ch, 1);
+ ret = gs_buf_put(port->port_write_buf, &ch, 1);
exit:
spin_unlock_irqrestore(&port->port_lock, flags);
+ return ret;
}
/*
@@ -1058,6 +918,23 @@ static void gs_set_termios(struct tty_struct *tty, struct ktermios *old)
{
}
+static const struct tty_operations gs_tty_ops = {
+ .open = gs_open,
+ .close = gs_close,
+ .write = gs_write,
+ .put_char = gs_put_char,
+ .flush_chars = gs_flush_chars,
+ .write_room = gs_write_room,
+ .ioctl = gs_ioctl,
+ .set_termios = gs_set_termios,
+ .throttle = gs_throttle,
+ .unthrottle = gs_unthrottle,
+ .break_ctl = gs_break,
+ .chars_in_buffer = gs_chars_in_buffer,
+};
+
+/*-------------------------------------------------------------------------*/
+
/*
* gs_send
*
@@ -1073,7 +950,6 @@ static int gs_send(struct gs_dev *dev)
unsigned long flags;
struct usb_ep *ep;
struct usb_request *req;
- struct gs_req_entry *req_entry;
if (dev == NULL) {
pr_err("gs_send: NULL device pointer\n");
@@ -1086,10 +962,8 @@ static int gs_send(struct gs_dev *dev)
while(!list_empty(&dev->dev_req_list)) {
- req_entry = list_entry(dev->dev_req_list.next,
- struct gs_req_entry, re_entry);
-
- req = req_entry->re_req;
+ req = list_entry(dev->dev_req_list.next,
+ struct usb_request, list);
len = gs_send_packet(dev, req->buf, ep->maxpacket);
@@ -1099,7 +973,7 @@ static int gs_send(struct gs_dev *dev)
*((unsigned char *)req->buf),
*((unsigned char *)req->buf+1),
*((unsigned char *)req->buf+2));
- list_del(&req_entry->re_entry);
+ list_del(&req->list);
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
@@ -1282,7 +1156,6 @@ requeue:
static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
{
struct gs_dev *dev = ep->driver_data;
- struct gs_req_entry *gs_req = req->context;
if (dev == NULL) {
pr_err("gs_write_complete: NULL device pointer\n");
@@ -1293,13 +1166,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
case 0:
/* normal completion */
requeue:
- if (gs_req == NULL) {
- pr_err("gs_write_complete: NULL request pointer\n");
- return;
- }
-
spin_lock(&dev->dev_lock);
- list_add(&gs_req->re_entry, &dev->dev_req_list);
+ list_add(&req->list, &dev->dev_req_list);
spin_unlock(&dev->dev_lock);
gs_send(dev);
@@ -1321,9 +1189,39 @@ requeue:
}
}
+/*-------------------------------------------------------------------------*/
+
/* Gadget Driver */
/*
+ * gs_unbind
+ *
+ * Called on module unload. Frees the control request and device
+ * structure.
+ */
+static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
+{
+ struct gs_dev *dev = get_gadget_data(gadget);
+
+ gs_device = NULL;
+
+ /* read/write requests already freed, only control request remains */
+ if (dev != NULL) {
+ if (dev->dev_ctrl_req != NULL) {
+ gs_free_req(gadget->ep0, dev->dev_ctrl_req);
+ dev->dev_ctrl_req = NULL;
+ }
+ gs_reset_config(dev);
+ gs_free_ports(dev);
+ kfree(dev);
+ set_gadget_data(gadget, NULL);
+ }
+
+ pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+ GS_VERSION_STR);
+}
+
+/*
* gs_bind
*
* Called on module load. Allocates and initializes the device
@@ -1355,19 +1253,23 @@ static int __init gs_bind(struct usb_gadget *gadget)
__constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
}
+ dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
+ if (dev == NULL)
+ return -ENOMEM;
+
usb_ep_autoconfig_reset(gadget);
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
if (!ep)
goto autoconf_fail;
- EP_IN_NAME = ep->name;
- ep->driver_data = ep; /* claim the endpoint */
+ dev->dev_in_ep = ep;
+ ep->driver_data = dev; /* claim the endpoint */
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
if (!ep)
goto autoconf_fail;
- EP_OUT_NAME = ep->name;
- ep->driver_data = ep; /* claim the endpoint */
+ dev->dev_out_ep = ep;
+ ep->driver_data = dev; /* claim the endpoint */
if (use_acm) {
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
@@ -1377,8 +1279,8 @@ static int __init gs_bind(struct usb_gadget *gadget)
}
gs_device_desc.idProduct = __constant_cpu_to_le16(
GS_CDC_PRODUCT_ID),
- EP_NOTIFY_NAME = ep->name;
- ep->driver_data = ep; /* claim the endpoint */
+ dev->dev_notify_ep = ep;
+ ep->driver_data = dev; /* claim the endpoint */
}
gs_device_desc.bDeviceClass = use_acm
@@ -1408,9 +1310,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
- if (dev == NULL)
- return -ENOMEM;
+ gs_device = dev;
snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
@@ -1434,8 +1334,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
gs_unbind(gadget);
return -ENOMEM;
}
- dev->dev_ctrl_req->complete = gs_setup_complete;
-
gadget->ep0->driver_data = dev;
pr_info("gs_bind: %s %s bound\n",
@@ -1444,97 +1342,11 @@ static int __init gs_bind(struct usb_gadget *gadget)
return 0;
autoconf_fail:
+ kfree(dev);
pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
return -ENODEV;
}
-/*
- * gs_unbind
- *
- * Called on module unload. Frees the control request and device
- * structure.
- */
-static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
-{
- struct gs_dev *dev = get_gadget_data(gadget);
-
- gs_device = NULL;
-
- /* read/write requests already freed, only control request remains */
- if (dev != NULL) {
- if (dev->dev_ctrl_req != NULL) {
- gs_free_req(gadget->ep0, dev->dev_ctrl_req);
- dev->dev_ctrl_req = NULL;
- }
- gs_free_ports(dev);
- if (dev->dev_notify_ep)
- usb_ep_disable(dev->dev_notify_ep);
- if (dev->dev_in_ep)
- usb_ep_disable(dev->dev_in_ep);
- if (dev->dev_out_ep)
- usb_ep_disable(dev->dev_out_ep);
- kfree(dev);
- set_gadget_data(gadget, NULL);
- }
-
- pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
- GS_VERSION_STR);
-}
-
-/*
- * gs_setup
- *
- * Implements all the control endpoint functionality that's not
- * handled in hardware or the hardware driver.
- *
- * Returns the size of the data sent to the host, or a negative
- * error number.
- */
-static int gs_setup(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl)
-{
- int ret = -EOPNOTSUPP;
- struct gs_dev *dev = get_gadget_data(gadget);
- struct usb_request *req = dev->dev_ctrl_req;
- u16 wIndex = le16_to_cpu(ctrl->wIndex);
- u16 wValue = le16_to_cpu(ctrl->wValue);
- u16 wLength = le16_to_cpu(ctrl->wLength);
-
- switch (ctrl->bRequestType & USB_TYPE_MASK) {
- case USB_TYPE_STANDARD:
- ret = gs_setup_standard(gadget,ctrl);
- break;
-
- case USB_TYPE_CLASS:
- ret = gs_setup_class(gadget,ctrl);
- break;
-
- default:
- pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
- "value=%04x, index=%04x, length=%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- wValue, wIndex, wLength);
- break;
- }
-
- /* respond with data transfer before status phase? */
- if (ret >= 0) {
- req->length = ret;
- req->zero = ret < wLength
- && (ret % gadget->ep0->maxpacket) == 0;
- ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (ret < 0) {
- pr_err("gs_setup: cannot queue response, ret=%d\n",
- ret);
- req->status = 0;
- gs_setup_complete(gadget->ep0, req);
- }
- }
-
- /* device either stalls (ret < 0) or reports success */
- return ret;
-}
-
static int gs_setup_standard(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl)
{
@@ -1664,6 +1476,42 @@ set_interface_done:
return ret;
}
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct gs_dev *dev = ep->driver_data;
+ struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+
+ switch (req->status) {
+ case 0:
+ /* normal completion */
+ if (req->actual != sizeof(port->port_line_coding))
+ usb_ep_set_halt(ep);
+ else if (port) {
+ struct usb_cdc_line_coding *value = req->buf;
+
+ /* REVISIT: we currently just remember this data.
+ * If we change that, (a) validate it first, then
+ * (b) update whatever hardware needs updating.
+ */
+ spin_lock(&port->port_lock);
+ port->port_line_coding = *value;
+ spin_unlock(&port->port_lock);
+ }
+ break;
+
+ case -ESHUTDOWN:
+ /* disconnect */
+ gs_free_req(ep, req);
+ break;
+
+ default:
+ /* unexpected */
+ break;
+ }
+ return;
+}
+
static int gs_setup_class(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl)
{
@@ -1677,18 +1525,14 @@ static int gs_setup_class(struct usb_gadget *gadget,
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
- /* FIXME Submit req to read the data; have its completion
- * handler copy that data to port->port_line_coding (iff
- * it's valid) and maybe pass it on. Until then, fail.
- */
- pr_warning("gs_setup: set_line_coding "
- "unuspported\n");
+ if (wLength != sizeof(struct usb_cdc_line_coding))
+ break;
+ ret = wLength;
+ req->complete = gs_setup_complete_set_line_coding;
break;
case USB_CDC_REQ_GET_LINE_CODING:
- port = dev->dev_port[0]; /* ACM only has one port */
- ret = min(wLength,
- (u16)sizeof(struct usb_cdc_line_coding));
+ ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
if (port) {
spin_lock(&port->port_lock);
memcpy(req->buf, &port->port_line_coding, ret);
@@ -1697,15 +1541,27 @@ static int gs_setup_class(struct usb_gadget *gadget,
break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- /* FIXME Submit req to read the data; have its completion
- * handler use that to set the state (iff it's valid) and
- * maybe pass it on. Until then, fail.
- */
- pr_warning("gs_setup: set_control_line_state "
- "unuspported\n");
+ if (wLength != 0)
+ break;
+ ret = 0;
+ if (port) {
+ /* REVISIT: we currently just remember this data.
+ * If we change that, update whatever hardware needs
+ * updating.
+ */
+ spin_lock(&port->port_lock);
+ port->port_handshake_bits = wValue;
+ spin_unlock(&port->port_lock);
+ }
break;
default:
+ /* NOTE: strictly speaking, we should accept AT-commands
+ * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+ * But our call management descriptor says we don't handle
+ * call management, so we should be able to get by without
+ * handling those "required" commands (except by stalling).
+ */
pr_err("gs_setup: unknown class request, "
"type=%02x, request=%02x, value=%04x, "
"index=%04x, length=%d\n",
@@ -1730,6 +1586,62 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
}
/*
+ * gs_setup
+ *
+ * Implements all the control endpoint functionality that's not
+ * handled in hardware or the hardware driver.
+ *
+ * Returns the size of the data sent to the host, or a negative
+ * error number.
+ */
+static int gs_setup(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int ret = -EOPNOTSUPP;
+ struct gs_dev *dev = get_gadget_data(gadget);
+ struct usb_request *req = dev->dev_ctrl_req;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
+
+ req->complete = gs_setup_complete;
+
+ switch (ctrl->bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ ret = gs_setup_standard(gadget, ctrl);
+ break;
+
+ case USB_TYPE_CLASS:
+ ret = gs_setup_class(gadget, ctrl);
+ break;
+
+ default:
+ pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+ "value=%04x, index=%04x, length=%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ wValue, wIndex, wLength);
+ break;
+ }
+
+ /* respond with data transfer before status phase? */
+ if (ret >= 0) {
+ req->length = ret;
+ req->zero = ret < wLength
+ && (ret % gadget->ep0->maxpacket) == 0;
+ ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ if (ret < 0) {
+ pr_err("gs_setup: cannot queue response, ret=%d\n",
+ ret);
+ req->status = 0;
+ gs_setup_complete(gadget->ep0, req);
+ }
+ }
+
+ /* device either stalls (ret < 0) or reports success */
+ return ret;
+}
+
+/*
* gs_disconnect
*
* Called when the device is disconnected. Frees the closed
@@ -1758,6 +1670,23 @@ static void gs_disconnect(struct usb_gadget *gadget)
pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
}
+static struct usb_gadget_driver gs_gadget_driver = {
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ .speed = USB_SPEED_HIGH,
+#else
+ .speed = USB_SPEED_FULL,
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ .function = GS_LONG_NAME,
+ .bind = gs_bind,
+ .unbind = gs_unbind,
+ .setup = gs_setup,
+ .disconnect = gs_disconnect,
+ .driver = {
+ .name = GS_SHORT_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
/*
* gs_set_config
*
@@ -1773,9 +1702,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
int ret = 0;
struct usb_gadget *gadget = dev->dev_gadget;
struct usb_ep *ep;
- struct usb_endpoint_descriptor *ep_desc;
+ struct usb_endpoint_descriptor *out, *in, *notify;
struct usb_request *req;
- struct gs_req_entry *req_entry;
if (dev == NULL) {
pr_err("gs_set_config: NULL device pointer\n");
@@ -1793,86 +1721,62 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
case GS_BULK_CONFIG_ID:
if (use_acm)
return -EINVAL;
- /* device specific optimizations */
- if (gadget_is_net2280(gadget))
- net2280_set_fifo_mode(gadget, 1);
break;
case GS_ACM_CONFIG_ID:
if (!use_acm)
return -EINVAL;
- /* device specific optimizations */
- if (gadget_is_net2280(gadget))
- net2280_set_fifo_mode(gadget, 1);
break;
default:
return -EINVAL;
}
- dev->dev_config = config;
-
- gadget_for_each_ep(ep, gadget) {
-
- if (EP_NOTIFY_NAME
- && strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
- ep_desc = choose_ep_desc(gadget,
+ in = choose_ep_desc(gadget,
+ &gs_highspeed_in_desc,
+ &gs_fullspeed_in_desc);
+ out = choose_ep_desc(gadget,
+ &gs_highspeed_out_desc,
+ &gs_fullspeed_out_desc);
+ notify = dev->dev_notify_ep
+ ? choose_ep_desc(gadget,
&gs_highspeed_notify_desc,
- &gs_fullspeed_notify_desc);
- ret = usb_ep_enable(ep,ep_desc);
- if (ret == 0) {
- ep->driver_data = dev;
- dev->dev_notify_ep = ep;
- dev->dev_notify_ep_desc = ep_desc;
- } else {
- pr_err("gs_set_config: cannot enable NOTIFY "
- "endpoint %s, ret=%d\n",
- ep->name, ret);
- goto exit_reset_config;
- }
- }
+ &gs_fullspeed_notify_desc)
+ : NULL;
- else if (strcmp(ep->name, EP_IN_NAME) == 0) {
- ep_desc = choose_ep_desc(gadget,
- &gs_highspeed_in_desc,
- &gs_fullspeed_in_desc);
- ret = usb_ep_enable(ep,ep_desc);
- if (ret == 0) {
- ep->driver_data = dev;
- dev->dev_in_ep = ep;
- dev->dev_in_ep_desc = ep_desc;
- } else {
- pr_err("gs_set_config: cannot enable IN "
- "endpoint %s, ret=%d\n",
- ep->name, ret);
- goto exit_reset_config;
- }
- }
-
- else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
- ep_desc = choose_ep_desc(gadget,
- &gs_highspeed_out_desc,
- &gs_fullspeed_out_desc);
- ret = usb_ep_enable(ep,ep_desc);
- if (ret == 0) {
- ep->driver_data = dev;
- dev->dev_out_ep = ep;
- dev->dev_out_ep_desc = ep_desc;
- } else {
- pr_err("gs_set_config: cannot enable OUT "
- "endpoint %s, ret=%d\n",
- ep->name, ret);
- goto exit_reset_config;
- }
- }
+ ret = usb_ep_enable(dev->dev_in_ep, in);
+ if (ret == 0) {
+ dev->dev_in_ep_desc = in;
+ } else {
+ pr_debug("%s: cannot enable %s %s, ret=%d\n",
+ __func__, "IN", dev->dev_in_ep->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->dev_out_ep, out);
+ if (ret == 0) {
+ dev->dev_out_ep_desc = out;
+ } else {
+ pr_debug("%s: cannot enable %s %s, ret=%d\n",
+ __func__, "OUT", dev->dev_out_ep->name, ret);
+fail0:
+ usb_ep_disable(dev->dev_in_ep);
+ return ret;
}
- if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
- || (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
- pr_err("gs_set_config: cannot find endpoints\n");
- ret = -ENODEV;
- goto exit_reset_config;
+ if (notify) {
+ ret = usb_ep_enable(dev->dev_notify_ep, notify);
+ if (ret == 0) {
+ dev->dev_notify_ep_desc = notify;
+ } else {
+ pr_debug("%s: cannot enable %s %s, ret=%d\n",
+ __func__, "NOTIFY",
+ dev->dev_notify_ep->name, ret);
+ usb_ep_disable(dev->dev_out_ep);
+ goto fail0;
+ }
}
+ dev->dev_config = config;
+
/* allocate and queue read requests */
ep = dev->dev_out_ep;
for (i=0; i<read_q_size && ret == 0; i++) {
@@ -1893,9 +1797,10 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
/* allocate write requests, and put on free list */
ep = dev->dev_in_ep;
for (i=0; i<write_q_size; i++) {
- if ((req_entry=gs_alloc_req_entry(ep, ep->maxpacket, GFP_ATOMIC))) {
- req_entry->re_req->complete = gs_write_complete;
- list_add(&req_entry->re_entry, &dev->dev_req_list);
+ req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+ if (req) {
+ req->complete = gs_write_complete;
+ list_add(&req->list, &dev->dev_req_list);
} else {
pr_err("gs_set_config: cannot allocate "
"write requests\n");
@@ -1904,6 +1809,11 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
}
+ /* REVISIT the ACM mode should be able to actually *issue* some
+ * notifications, for at least serial state change events if
+ * not also for network connection; say so in bmCapabilities.
+ */
+
pr_info("gs_set_config: %s configured, %s speed %s config\n",
GS_LONG_NAME,
gadget->speed == USB_SPEED_HIGH ? "high" : "full",
@@ -1928,7 +1838,7 @@ exit_reset_config:
*/
static void gs_reset_config(struct gs_dev *dev)
{
- struct gs_req_entry *req_entry;
+ struct usb_request *req;
if (dev == NULL) {
pr_err("gs_reset_config: NULL device pointer\n");
@@ -1942,26 +1852,18 @@ static void gs_reset_config(struct gs_dev *dev)
/* free write requests on the free list */
while(!list_empty(&dev->dev_req_list)) {
- req_entry = list_entry(dev->dev_req_list.next,
- struct gs_req_entry, re_entry);
- list_del(&req_entry->re_entry);
- gs_free_req_entry(dev->dev_in_ep, req_entry);
+ req = list_entry(dev->dev_req_list.next,
+ struct usb_request, list);
+ list_del(&req->list);
+ gs_free_req(dev->dev_in_ep, req);
}
/* disable endpoints, forcing completion of pending i/o; */
/* completion handlers free their requests in this case */
- if (dev->dev_notify_ep) {
+ if (dev->dev_notify_ep)
usb_ep_disable(dev->dev_notify_ep);
- dev->dev_notify_ep = NULL;
- }
- if (dev->dev_in_ep) {
- usb_ep_disable(dev->dev_in_ep);
- dev->dev_in_ep = NULL;
- }
- if (dev->dev_out_ep) {
- usb_ep_disable(dev->dev_out_ep);
- dev->dev_out_ep = NULL;
- }
+ usb_ep_disable(dev->dev_in_ep);
+ usb_ep_disable(dev->dev_out_ep);
}
/*
@@ -2055,46 +1957,6 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
}
/*
- * gs_alloc_req_entry
- *
- * Allocates a request and its buffer, using the given
- * endpoint, buffer len, and kmalloc flags.
- */
-static struct gs_req_entry *
-gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
-{
- struct gs_req_entry *req;
-
- req = kmalloc(sizeof(struct gs_req_entry), kmalloc_flags);
- if (req == NULL)
- return NULL;
-
- req->re_req = gs_alloc_req(ep, len, kmalloc_flags);
- if (req->re_req == NULL) {
- kfree(req);
- return NULL;
- }
-
- req->re_req->context = req;
-
- return req;
-}
-
-/*
- * gs_free_req_entry
- *
- * Frees a request and its buffer.
- */
-static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
-{
- if (ep != NULL && req != NULL) {
- if (req->re_req != NULL)
- gs_free_req(ep, req->re_req);
- kfree(req);
- }
-}
-
-/*
* gs_alloc_ports
*
* Allocate all ports and set the gs_dev struct to point to them.
@@ -2175,6 +2037,8 @@ static void gs_free_ports(struct gs_dev *dev)
}
}
+/*-------------------------------------------------------------------------*/
+
/* Circular Buffer */
/*
@@ -2335,3 +2199,77 @@ gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
return count;
}
+
+/*-------------------------------------------------------------------------*/
+
+static struct tty_driver *gs_tty_driver;
+
+/*
+ * gs_module_init
+ *
+ * Register as a USB gadget driver and a tty driver.
+ */
+static int __init gs_module_init(void)
+{
+ int i;
+ int retval;
+
+ retval = usb_gadget_register_driver(&gs_gadget_driver);
+ if (retval) {
+ pr_err("gs_module_init: cannot register gadget driver, "
+ "ret=%d\n", retval);
+ return retval;
+ }
+
+ gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS);
+ if (!gs_tty_driver)
+ return -ENOMEM;
+ gs_tty_driver->owner = THIS_MODULE;
+ gs_tty_driver->driver_name = GS_SHORT_NAME;
+ gs_tty_driver->name = "ttygs";
+ gs_tty_driver->major = GS_MAJOR;
+ gs_tty_driver->minor_start = GS_MINOR_START;
+ gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ gs_tty_driver->init_termios = tty_std_termios;
+ /* must match GS_DEFAULT_DTE_RATE and friends */
+ gs_tty_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ gs_tty_driver->init_termios.c_ispeed = GS_DEFAULT_DTE_RATE;
+ gs_tty_driver->init_termios.c_ospeed = GS_DEFAULT_DTE_RATE;
+ tty_set_operations(gs_tty_driver, &gs_tty_ops);
+
+ for (i = 0; i < GS_NUM_PORTS; i++)
+ mutex_init(&gs_open_close_lock[i]);
+
+ retval = tty_register_driver(gs_tty_driver);
+ if (retval) {
+ usb_gadget_unregister_driver(&gs_gadget_driver);
+ put_tty_driver(gs_tty_driver);
+ pr_err("gs_module_init: cannot register tty driver, "
+ "ret=%d\n", retval);
+ return retval;
+ }
+
+ pr_info("gs_module_init: %s %s loaded\n",
+ GS_LONG_NAME, GS_VERSION_STR);
+ return 0;
+}
+module_init(gs_module_init);
+
+/*
+ * gs_module_exit
+ *
+ * Unregister as a tty driver and a USB gadget driver.
+ */
+static void __exit gs_module_exit(void)
+{
+ tty_unregister_driver(gs_tty_driver);
+ put_tty_driver(gs_tty_driver);
+ usb_gadget_unregister_driver(&gs_gadget_driver);
+
+ pr_info("gs_module_exit: %s %s unloaded\n",
+ GS_LONG_NAME, GS_VERSION_STR);
+}
+module_exit(gs_module_exit);
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 878e428a0ec1..4154be375c7a 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -74,7 +74,7 @@ static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
goto fail;
} else
uchar = c;
- put_unaligned (cpu_to_le16 (uchar), cp++);
+ put_unaligned_le16(uchar, cp++);
count++;
len--;
}
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index d3d4f4048e6c..fce4924dbbe8 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -23,9 +23,7 @@
/*
* Gadget Zero only needs two bulk endpoints, and is an example of how you
* can write a hardware-agnostic gadget driver running inside a USB device.
- *
- * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
- * affect most of the driver.
+ * Some hardware details are visible, but don't affect most of the driver.
*
* Use it with the Linux host/master side "usbtest" driver to get a basic
* functional test of your device-side usb stack, or with "usb-skeleton".
@@ -37,6 +35,7 @@
* buflen=N default N=4096, buffer size used
* qlen=N default N=32, how many buffers in the loopback queue
* loopdefault default false, list loopback config first
+ * autoresume=N default N=0, seconds before triggering remote wakeup
*
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
@@ -62,13 +61,13 @@
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "Lughnasadh, 2007"
+#define DRIVER_VERSION "Earth Day 2008"
-static const char shortname [] = "zero";
-static const char longname [] = "Gadget Zero";
+static const char shortname[] = "zero";
+static const char longname[] = "Gadget Zero";
-static const char source_sink [] = "source and sink data";
-static const char loopback [] = "loop input to output";
+static const char source_sink[] = "source and sink data";
+static const char loopback[] = "loop input to output";
/*-------------------------------------------------------------------------*/
@@ -120,16 +119,16 @@ static unsigned buflen = 4096;
static unsigned qlen = 32;
static unsigned pattern = 0;
-module_param (buflen, uint, S_IRUGO);
-module_param (qlen, uint, S_IRUGO);
-module_param (pattern, uint, S_IRUGO|S_IWUSR);
+module_param(buflen, uint, S_IRUGO);
+module_param(qlen, uint, S_IRUGO);
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
/*
* if it's nonzero, autoresume says how many seconds to wait
* before trying to wake up the host after suspend.
*/
static unsigned autoresume = 0;
-module_param (autoresume, uint, 0);
+module_param(autoresume, uint, 0);
/*
* Normally the "loopback" configuration is second (index 1) so
@@ -138,8 +137,7 @@ module_param (autoresume, uint, 0);
* Or controllers (like superh) that only support one config.
*/
static int loopdefault = 0;
-
-module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
/*-------------------------------------------------------------------------*/
@@ -176,24 +174,22 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
#define CONFIG_SOURCE_SINK 3
#define CONFIG_LOOPBACK 2
-static struct usb_device_descriptor
-device_desc = {
+static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
- .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
- .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIAL,
.bNumConfigurations = 2,
};
-static struct usb_config_descriptor
-source_sink_config = {
+static struct usb_config_descriptor source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -205,8 +201,7 @@ source_sink_config = {
.bMaxPower = 1, /* self-powered */
};
-static struct usb_config_descriptor
-loopback_config = {
+static struct usb_config_descriptor loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -218,8 +213,7 @@ loopback_config = {
.bMaxPower = 1, /* self-powered */
};
-static struct usb_otg_descriptor
-otg_descriptor = {
+static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
@@ -228,8 +222,7 @@ otg_descriptor = {
/* one interface in each configuration */
-static const struct usb_interface_descriptor
-source_sink_intf = {
+static const struct usb_interface_descriptor source_sink_intf = {
.bLength = sizeof source_sink_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -238,8 +231,7 @@ source_sink_intf = {
.iInterface = STRING_SOURCE_SINK,
};
-static const struct usb_interface_descriptor
-loopback_intf = {
+static const struct usb_interface_descriptor loopback_intf = {
.bLength = sizeof loopback_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -250,8 +242,7 @@ loopback_intf = {
/* two full speed bulk endpoints; their use is config-dependent */
-static struct usb_endpoint_descriptor
-fs_source_desc = {
+static struct usb_endpoint_descriptor fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -259,8 +250,7 @@ fs_source_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor
-fs_sink_desc = {
+static struct usb_endpoint_descriptor fs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -268,7 +258,7 @@ fs_sink_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static const struct usb_descriptor_header *fs_source_sink_function [] = {
+static const struct usb_descriptor_header *fs_source_sink_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
@@ -276,7 +266,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = {
NULL,
};
-static const struct usb_descriptor_header *fs_loopback_function [] = {
+static const struct usb_descriptor_header *fs_loopback_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
@@ -293,36 +283,33 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
* for the config descriptor.
*/
-static struct usb_endpoint_descriptor
-hs_source_desc = {
+static struct usb_endpoint_descriptor hs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (512),
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor
-hs_sink_desc = {
+static struct usb_endpoint_descriptor hs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (512),
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
};
-static struct usb_qualifier_descriptor
-dev_qualifier = {
+static struct usb_qualifier_descriptor dev_qualifier = {
.bLength = sizeof dev_qualifier,
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.bNumConfigurations = 2,
};
-static const struct usb_descriptor_header *hs_source_sink_function [] = {
+static const struct usb_descriptor_header *hs_source_sink_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &hs_source_desc,
@@ -330,7 +317,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = {
NULL,
};
-static const struct usb_descriptor_header *hs_loopback_function [] = {
+static const struct usb_descriptor_header *hs_loopback_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &hs_source_desc,
@@ -355,7 +342,7 @@ static char serial[] = "0123456789.0123456789.0123456789";
/* static strings, in UTF-8 */
-static struct usb_string strings [] = {
+static struct usb_string strings[] = {
{ STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, longname, },
{ STRING_SERIAL, serial, },
@@ -364,7 +351,7 @@ static struct usb_string strings [] = {
{ } /* end of list */
};
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab = {
.language = 0x0409, /* en-us */
.strings = strings,
};
@@ -387,8 +374,7 @@ static struct usb_gadget_strings stringtab = {
* high bandwidth modes at high speed. (Maybe work like Intel's test
* device?)
*/
-static int
-config_buf (struct usb_gadget *gadget,
+static int config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
int is_source_sink;
@@ -419,7 +405,7 @@ config_buf (struct usb_gadget *gadget,
if (!gadget_is_otg(gadget))
function++;
- len = usb_gadget_config_buf (is_source_sink
+ len = usb_gadget_config_buf(is_source_sink
? &source_sink_config
: &loopback_config,
buf, USB_BUFSIZ, function);
@@ -431,27 +417,26 @@ config_buf (struct usb_gadget *gadget,
/*-------------------------------------------------------------------------*/
-static struct usb_request *
-alloc_ep_req (struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
- req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req) {
req->length = length;
req->buf = kmalloc(length, GFP_ATOMIC);
if (!req->buf) {
- usb_ep_free_request (ep, req);
+ usb_ep_free_request(ep, req);
req = NULL;
}
}
return req;
}
-static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
kfree(req->buf);
- usb_ep_free_request (ep, req);
+ usb_ep_free_request(ep, req);
}
/*-------------------------------------------------------------------------*/
@@ -472,7 +457,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/* optionally require specific source/sink data patterns */
static int
-check_read_data (
+check_read_data(
struct zero_dev *dev,
struct usb_ep *ep,
struct usb_request *req
@@ -498,8 +483,8 @@ check_read_data (
continue;
break;
}
- ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
- usb_ep_set_halt (ep);
+ ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
+ usb_ep_set_halt(ep);
return -EINVAL;
}
return 0;
@@ -512,7 +497,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
switch (pattern) {
case 0:
- memset (req->buf, 0, req->length);
+ memset(req->buf, 0, req->length);
break;
case 1:
for (i = 0; i < req->length; i++)
@@ -525,7 +510,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
* irq delay between end of one request and start of the next.
* that prevents using hardware dma queues.
*/
-static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
+static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
{
struct zero_dev *dev = ep->driver_data;
int status = req->status;
@@ -534,8 +519,8 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
case 0: /* normal completion? */
if (ep == dev->out_ep) {
- check_read_data (dev, ep, req);
- memset (req->buf, 0x55, req->length);
+ check_read_data(dev, ep, req);
+ memset(req->buf, 0x55, req->length);
} else
reinit_write_data(ep, req);
break;
@@ -544,11 +529,11 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length);
if (ep == dev->out_ep)
- check_read_data (dev, ep, req);
- free_ep_req (ep, req);
+ check_read_data(dev, ep, req);
+ free_ep_req(ep, req);
return;
case -EOVERFLOW: /* buffer overrun on read means that
@@ -557,18 +542,18 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
*/
default:
#if 1
- DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+ DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
#endif
case -EREMOTEIO: /* short read */
break;
}
- status = usb_ep_queue (ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
- ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
+ ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
ep->name, req->length, status);
- usb_ep_set_halt (ep);
+ usb_ep_set_halt(ep);
/* FIXME recover later ... somehow */
}
}
@@ -578,24 +563,24 @@ static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
struct usb_request *req;
int status;
- req = alloc_ep_req (ep, buflen);
+ req = alloc_ep_req(ep, buflen);
if (!req)
return NULL;
- memset (req->buf, 0, req->length);
+ memset(req->buf, 0, req->length);
req->complete = source_sink_complete;
- if (strcmp (ep->name, EP_IN_NAME) == 0)
+ if (strcmp(ep->name, EP_IN_NAME) == 0)
reinit_write_data(ep, req);
else
- memset (req->buf, 0x55, req->length);
+ memset(req->buf, 0x55, req->length);
status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
- ERROR (dev, "start %s --> %d\n", ep->name, status);
- free_ep_req (ep, req);
+ ERROR(dev, "start %s --> %d\n", ep->name, status);
+ free_ep_req(ep, req);
req = NULL;
}
@@ -608,34 +593,34 @@ static int set_source_sink_config(struct zero_dev *dev)
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
- gadget_for_each_ep (ep, gadget) {
+ gadget_for_each_ep(ep, gadget) {
const struct usb_endpoint_descriptor *d;
/* one endpoint writes (sources) zeroes in (to the host) */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
- usb_ep_disable (ep);
+ usb_ep_disable(ep);
result = -EIO;
}
/* one endpoint reads (sinks) anything out (from the host) */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
+ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
- usb_ep_disable (ep);
+ usb_ep_disable(ep);
result = -EIO;
}
@@ -644,11 +629,11 @@ static int set_source_sink_config(struct zero_dev *dev)
continue;
/* stop on error */
- ERROR (dev, "can't start %s, result %d\n", ep->name, result);
+ ERROR(dev, "can't start %s, result %d\n", ep->name, result);
break;
}
if (result == 0)
- DBG (dev, "buflen %d\n", buflen);
+ DBG(dev, "buflen %d\n", buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -656,7 +641,7 @@ static int set_source_sink_config(struct zero_dev *dev)
/*-------------------------------------------------------------------------*/
-static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
+static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
{
struct zero_dev *dev = ep->driver_data;
int status = req->status;
@@ -668,19 +653,19 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
req->length = req->actual;
- status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
if (status == 0)
return;
/* "should never get here" */
- ERROR (dev, "can't loop %s to %s: %d\n",
+ ERROR(dev, "can't loop %s to %s: %d\n",
ep->name, dev->in_ep->name,
status);
}
/* queue the buffer for some later OUT packet */
req->length = buflen;
- status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
if (status == 0)
return;
@@ -688,7 +673,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
/* FALLTHROUGH */
default:
- ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+ ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
/* FALLTHROUGH */
@@ -700,7 +685,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- free_ep_req (ep, req);
+ free_ep_req(ep, req);
return;
}
}
@@ -711,13 +696,13 @@ static int set_loopback_config(struct zero_dev *dev)
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
- gadget_for_each_ep (ep, gadget) {
+ gadget_for_each_ep(ep, gadget) {
const struct usb_endpoint_descriptor *d;
/* one endpoint writes data back IN to the host */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->in_ep = ep;
@@ -725,9 +710,9 @@ static int set_loopback_config(struct zero_dev *dev)
}
/* one endpoint just reads OUT packets */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
+ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->out_ep = ep;
@@ -739,7 +724,7 @@ static int set_loopback_config(struct zero_dev *dev)
continue;
/* stop on error */
- ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+ ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
break;
}
@@ -753,19 +738,19 @@ static int set_loopback_config(struct zero_dev *dev)
ep = dev->out_ep;
for (i = 0; i < qlen && result == 0; i++) {
- req = alloc_ep_req (ep, buflen);
+ req = alloc_ep_req(ep, buflen);
if (req) {
req->complete = loopback_complete;
- result = usb_ep_queue (ep, req, GFP_ATOMIC);
+ result = usb_ep_queue(ep, req, GFP_ATOMIC);
if (result)
- DBG (dev, "%s queue req --> %d\n",
+ DBG(dev, "%s queue req --> %d\n",
ep->name, result);
} else
result = -ENOMEM;
}
}
if (result == 0)
- DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+ DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -773,26 +758,26 @@ static int set_loopback_config(struct zero_dev *dev)
/*-------------------------------------------------------------------------*/
-static void zero_reset_config (struct zero_dev *dev)
+static void zero_reset_config(struct zero_dev *dev)
{
if (dev->config == 0)
return;
- DBG (dev, "reset config\n");
+ DBG(dev, "reset config\n");
/* just disable endpoints, forcing completion of pending i/o.
* all our completion handlers free their requests in this case.
*/
if (dev->in_ep) {
- usb_ep_disable (dev->in_ep);
+ usb_ep_disable(dev->in_ep);
dev->in_ep = NULL;
}
if (dev->out_ep) {
- usb_ep_disable (dev->out_ep);
+ usb_ep_disable(dev->out_ep);
dev->out_ep = NULL;
}
dev->config = 0;
- del_timer (&dev->resume);
+ del_timer(&dev->resume);
}
/* change our operational config. this code must agree with the code
@@ -813,12 +798,12 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
if (number == dev->config)
return 0;
- if (gadget_is_sa1100 (gadget) && dev->config) {
+ if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
- zero_reset_config (dev);
+ zero_reset_config(dev);
switch (number) {
case CONFIG_SOURCE_SINK:
@@ -837,7 +822,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
if (!result && (!dev->in_ep || !dev->out_ep))
result = -ENODEV;
if (result)
- zero_reset_config (dev);
+ zero_reset_config(dev);
else {
char *speed;
@@ -849,7 +834,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
}
dev->config = number;
- INFO (dev, "%s speed config #%d: %s\n", speed, number,
+ INFO(dev, "%s speed config #%d: %s\n", speed, number,
(number == CONFIG_SOURCE_SINK)
? source_sink : loopback);
}
@@ -858,10 +843,10 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
/*-------------------------------------------------------------------------*/
-static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
- DBG ((struct zero_dev *) ep->driver_data,
+ DBG((struct zero_dev *) ep->driver_data,
"setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
}
@@ -874,9 +859,9 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
* the work is in config-specific setup.
*/
static int
-zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
@@ -895,14 +880,14 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
switch (w_value >> 8) {
case USB_DT_DEVICE:
- value = min (w_length, (u16) sizeof device_desc);
- memcpy (req->buf, &device_desc, value);
+ value = min(w_length, (u16) sizeof device_desc);
+ memcpy(req->buf, &device_desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget))
break;
- value = min (w_length, (u16) sizeof dev_qualifier);
- memcpy (req->buf, &dev_qualifier, value);
+ value = min(w_length, (u16) sizeof dev_qualifier);
+ memcpy(req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
@@ -910,11 +895,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
// FALLTHROUGH
case USB_DT_CONFIG:
- value = config_buf (gadget, req->buf,
+ value = config_buf(gadget, req->buf,
w_value >> 8,
w_value & 0xff);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
@@ -923,10 +908,10 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* add string tables for other languages, using
* any UTF-8 characters
*/
- value = usb_gadget_get_string (&stringtab,
+ value = usb_gadget_get_string(&stringtab,
w_value & 0xff, req->buf);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min(w_length, (u16) value);
break;
}
break;
@@ -936,20 +921,20 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (ctrl->bRequestType != 0)
goto unknown;
if (gadget->a_hnp_support)
- DBG (dev, "HNP available\n");
+ DBG(dev, "HNP available\n");
else if (gadget->a_alt_hnp_support)
- DBG (dev, "HNP needs a different root port\n");
+ DBG(dev, "HNP needs a different root port\n");
else
- VDBG (dev, "HNP inactive\n");
- spin_lock (&dev->lock);
+ VDBG(dev, "HNP inactive\n");
+ spin_lock(&dev->lock);
value = zero_set_config(dev, w_value);
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
*(u8 *)req->buf = dev->config;
- value = min (w_length, (u16) 1);
+ value = min(w_length, (u16) 1);
break;
/* until we add altsetting support, or other interfaces,
@@ -959,7 +944,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
- spin_lock (&dev->lock);
+ spin_lock(&dev->lock);
if (dev->config && w_index == 0 && w_value == 0) {
u8 config = dev->config;
@@ -970,11 +955,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* if we had more than one interface we couldn't
* use this "reset the config" shortcut.
*/
- zero_reset_config (dev);
+ zero_reset_config(dev);
zero_set_config(dev, config);
value = 0;
}
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->lock);
break;
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
@@ -986,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
}
*(u8 *)req->buf = 0;
- value = min (w_length, (u16) 1);
+ value = min(w_length, (u16) 1);
break;
/*
@@ -1018,7 +1003,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
default:
unknown:
- VDBG (dev,
+ VDBG(dev,
"unknown control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
@@ -1028,11 +1013,11 @@ unknown:
if (value >= 0) {
req->length = value;
req->zero = value < w_length;
- value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
- DBG (dev, "ep_queue --> %d\n", value);
+ DBG(dev, "ep_queue --> %d\n", value);
req->status = 0;
- zero_setup_complete (gadget->ep0, req);
+ zero_setup_complete(gadget->ep0, req);
}
}
@@ -1040,28 +1025,26 @@ unknown:
return value;
}
-static void
-zero_disconnect (struct usb_gadget *gadget)
+static void zero_disconnect(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
unsigned long flags;
- spin_lock_irqsave (&dev->lock, flags);
- zero_reset_config (dev);
+ spin_lock_irqsave(&dev->lock, flags);
+ zero_reset_config(dev);
/* a more significant application might have some non-usb
* activities to quiesce here, saving resources like power
* or pushing the notification up a network stack.
*/
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->lock, flags);
/* next we may get setup() calls to enumerate new connections;
* or an unbind() during shutdown (including removing module).
*/
}
-static void
-zero_autoresume (unsigned long _dev)
+static void zero_autoresume(unsigned long _dev)
{
struct zero_dev *dev = (struct zero_dev *) _dev;
int status;
@@ -1070,32 +1053,30 @@ zero_autoresume (unsigned long _dev)
* more significant than just a timer firing...
*/
if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
- status = usb_gadget_wakeup (dev->gadget);
- DBG (dev, "wakeup --> %d\n", status);
+ status = usb_gadget_wakeup(dev->gadget);
+ DBG(dev, "wakeup --> %d\n", status);
}
}
/*-------------------------------------------------------------------------*/
-static void /* __init_or_exit */
-zero_unbind (struct usb_gadget *gadget)
+static void zero_unbind(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
- DBG (dev, "unbind\n");
+ DBG(dev, "unbind\n");
/* we've already been disconnected ... no i/o is active */
if (dev->req) {
dev->req->length = USB_BUFSIZ;
- free_ep_req (gadget->ep0, dev->req);
+ free_ep_req(gadget->ep0, dev->req);
}
- del_timer_sync (&dev->resume);
- kfree (dev);
- set_gadget_data (gadget, NULL);
+ del_timer_sync(&dev->resume);
+ kfree(dev);
+ set_gadget_data(gadget, NULL);
}
-static int __init
-zero_bind (struct usb_gadget *gadget)
+static int __init zero_bind(struct usb_gadget *gadget)
{
struct zero_dev *dev;
struct usb_ep *ep;
@@ -1111,8 +1092,8 @@ zero_bind (struct usb_gadget *gadget)
* autoconfigure on any sane usb controller driver,
* but there may also be important quirks to address.
*/
- usb_ep_autoconfig_reset (gadget);
- ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+ usb_ep_autoconfig_reset(gadget);
+ ep = usb_ep_autoconfig(gadget, &fs_source_desc);
if (!ep) {
autoconf_fail:
pr_err("%s: can't autoconfigure on %s\n",
@@ -1122,15 +1103,15 @@ autoconf_fail:
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
- ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+ ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
EP_OUT_NAME = ep->name;
ep->driver_data = ep; /* claim */
- gcnum = usb_gadget_controller_number (gadget);
+ gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
@@ -1141,7 +1122,7 @@ autoconf_fail:
*/
pr_warning("%s: controller '%s' not recognized\n",
shortname, gadget->name);
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
}
@@ -1149,12 +1130,16 @@ autoconf_fail:
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- spin_lock_init (&dev->lock);
+ spin_lock_init(&dev->lock);
dev->gadget = gadget;
- set_gadget_data (gadget, dev);
+ set_gadget_data(gadget, dev);
+
+ init_timer(&dev->resume);
+ dev->resume.function = zero_autoresume;
+ dev->resume.data = (unsigned long) dev;
/* preallocate control response and buffer */
- dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
@@ -1182,11 +1167,8 @@ autoconf_fail:
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- usb_gadget_set_selfpowered (gadget);
+ usb_gadget_set_selfpowered(gadget);
- init_timer (&dev->resume);
- dev->resume.function = zero_autoresume;
- dev->resume.data = (unsigned long) dev;
if (autoresume) {
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1194,45 +1176,43 @@ autoconf_fail:
gadget->ep0->driver_data = dev;
- INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
- INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
+ INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
EP_OUT_NAME, EP_IN_NAME);
- snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name);
return 0;
enomem:
- zero_unbind (gadget);
+ zero_unbind(gadget);
return -ENOMEM;
}
/*-------------------------------------------------------------------------*/
-static void
-zero_suspend (struct usb_gadget *gadget)
+static void zero_suspend(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
if (gadget->speed == USB_SPEED_UNKNOWN)
return;
if (autoresume) {
- mod_timer (&dev->resume, jiffies + (HZ * autoresume));
- DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+ mod_timer(&dev->resume, jiffies + (HZ * autoresume));
+ DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
} else
- DBG (dev, "suspend\n");
+ DBG(dev, "suspend\n");
}
-static void
-zero_resume (struct usb_gadget *gadget)
+static void zero_resume(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
- DBG (dev, "resume\n");
- del_timer (&dev->resume);
+ DBG(dev, "resume\n");
+ del_timer(&dev->resume);
}
@@ -1264,15 +1244,15 @@ MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
-static int __init init (void)
+static int __init init(void)
{
- return usb_gadget_register_driver (&zero_driver);
+ return usb_gadget_register_driver(&zero_driver);
}
-module_init (init);
+module_init(init);
-static void __exit cleanup (void)
+static void __exit cleanup(void)
{
- usb_gadget_unregister_driver (&zero_driver);
+ usb_gadget_unregister_driver(&zero_driver);
}
-module_exit (cleanup);
+module_exit(cleanup);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 0b87480dd713..1ef6df395e0c 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -4,6 +4,19 @@
comment "USB Host Controller Drivers"
depends on USB
+config USB_C67X00_HCD
+ tristate "Cypress C67x00 HCD support"
+ depends on USB
+ help
+ The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
+ host/peripheral/OTG USB controllers.
+
+ Enable this option to support this chip in host controller mode.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called c67x00.
+
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
depends on USB && USB_ARCH_HAS_EHCI
@@ -95,6 +108,32 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
+config USB_ISP1760_HCD
+ tristate "ISP 1760 HCD support"
+ depends on USB && EXPERIMENTAL
+ ---help---
+ The ISP1760 chip is a USB 2.0 host controller.
+
+ This driver does not support isochronous transfers or OTG.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1760-hcd.
+
+config USB_ISP1760_PCI
+ bool "Support for the PCI bus"
+ depends on USB_ISP1760_HCD && PCI
+ ---help---
+ Enables support for the device present on the PCI bus.
+ This should only be required if you happen to have the eval kit from
+ NXP and you are going to test it.
+
+config USB_ISP1760_OF
+ bool "Support for the OF platform bus"
+ depends on USB_ISP1760_HCD && PPC_OF
+ ---help---
+ Enables support for the device present on the PowerPC
+ OpenFirmware platform bus.
+
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index bb8e9d44f371..f1edda2dcfde 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
+isp1760-objs := isp1760-hcd.o isp1760-if.o
+
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
@@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-
+obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index f13d1029aeb2..382587c4457c 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -770,7 +770,7 @@ static int ehci_hub_control (
if (status & ~0xffff) /* only if wPortChange is interesting */
#endif
dbg_port (ehci, "GetStatus", wIndex + 1, temp);
- put_unaligned(cpu_to_le32 (status), (__le32 *) buf);
+ put_unaligned_le32(status, buf);
break;
case SetHubFeature:
switch (wValue) {
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
new file mode 100644
index 000000000000..c9cec8738261
--- /dev/null
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -0,0 +1,2231 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * However, the code might contain some bugs. What doesn't work for sure is:
+ * - ISO
+ * - OTG
+ e The interrupt line is configured as active low, level.
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+
+struct isp1760_hcd {
+ u32 hcs_params;
+ spinlock_t lock;
+ struct inter_packet_info atl_ints[32];
+ struct inter_packet_info int_ints[32];
+ struct memory_chunk memory_pool[BLOCKS];
+
+ /* periodic schedule support */
+#define DEFAULT_I_TDPS 1024
+ unsigned periodic_size;
+ unsigned i_thresh;
+ unsigned long reset_done;
+ unsigned long next_statechange;
+};
+
+static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+ return (struct isp1760_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv)
+{
+ return container_of((void *) priv, struct usb_hcd, hcd_priv);
+}
+
+/* Section 2.2 Host Controller Capability Registers */
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+
+/* Section 2.3 Host Controller Operational Registers */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+#define STS_PCD (1<<2) /* port change detect */
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC)
+
+struct isp1760_qtd {
+ struct isp1760_qtd *hw_next;
+ u8 packet_type;
+ u8 toggle;
+
+ void *data_buffer;
+ /* the rest is HCD-private */
+ struct list_head qtd_list;
+ struct urb *urb;
+ size_t length;
+
+ /* isp special*/
+ u32 status;
+#define URB_COMPLETE_NOTIFY (1 << 0)
+#define URB_ENQUEUED (1 << 1)
+#define URB_TYPE_ATL (1 << 2)
+#define URB_TYPE_INT (1 << 3)
+};
+
+struct isp1760_qh {
+ /* first part defined by EHCI spec */
+ struct list_head qtd_list;
+ struct isp1760_hcd *priv;
+
+ /* periodic schedule info */
+ unsigned short period; /* polling interval */
+ struct usb_device *dev;
+
+ u32 toggle;
+ u32 ping;
+};
+
+#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED)
+
+static unsigned int isp1760_readl(__u32 __iomem *regs)
+{
+ return readl(regs);
+}
+
+static void isp1760_writel(const unsigned int val, __u32 __iomem *regs)
+{
+ writel(val, regs);
+}
+
+/*
+ * The next two copy via MMIO data to/from the device. memcpy_{to|from}io()
+ * doesn't quite work because some people have to enforce 32-bit access
+ */
+static void priv_read_copy(struct isp1760_hcd *priv, u32 *src,
+ __u32 __iomem *dst, u32 offset, u32 len)
+{
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+ u32 val;
+ u8 *buff8;
+
+ if (!src) {
+ printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len);
+ return;
+ }
+ isp1760_writel(offset, hcd->regs + HC_MEMORY_REG);
+ /* XXX
+ * 90nsec delay, the spec says something how this could be avoided.
+ */
+ mdelay(1);
+
+ while (len >= 4) {
+ *src = __raw_readl(dst);
+ len -= 4;
+ src++;
+ dst++;
+ }
+
+ if (!len)
+ return;
+
+ /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
+ * allocated.
+ */
+ val = isp1760_readl(dst);
+
+ buff8 = (u8 *)src;
+ while (len) {
+
+ *buff8 = val;
+ val >>= 8;
+ len--;
+ buff8++;
+ }
+}
+
+static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src,
+ __u32 __iomem *dst, u32 len)
+{
+ while (len >= 4) {
+ __raw_writel(*src, dst);
+ len -= 4;
+ src++;
+ dst++;
+ }
+
+ if (!len)
+ return;
+ /* in case we have 3, 2 or 1 by left. The buffer is allocated and the
+ * extra bytes should not be read by the HW
+ */
+
+ __raw_writel(*src, dst);
+}
+
+/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+static void init_memory(struct isp1760_hcd *priv)
+{
+ int i;
+ u32 payload;
+
+ payload = 0x1000;
+ for (i = 0; i < BLOCK_1_NUM; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_1_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+
+ for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_2_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+
+ for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_3_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+ BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE);
+}
+
+static u32 alloc_mem(struct isp1760_hcd *priv, u32 size)
+{
+ int i;
+
+ if (!size)
+ return ISP1760_NULL_POINTER;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].size >= size &&
+ priv->memory_pool[i].free) {
+
+ priv->memory_pool[i].free = 0;
+ return priv->memory_pool[i].start;
+ }
+ }
+
+ printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n",
+ size);
+ printk(KERN_ERR "Current memory map:\n");
+ for (i = 0; i < BLOCKS; i++) {
+ printk(KERN_ERR "Pool %2d size %4d status: %d\n",
+ i, priv->memory_pool[i].size,
+ priv->memory_pool[i].free);
+ }
+ /* XXX maybe -ENOMEM could be possible */
+ BUG();
+ return 0;
+}
+
+static void free_mem(struct isp1760_hcd *priv, u32 mem)
+{
+ int i;
+
+ if (mem == ISP1760_NULL_POINTER)
+ return;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].start == mem) {
+
+ BUG_ON(priv->memory_pool[i].free);
+
+ priv->memory_pool[i].free = 1;
+ return ;
+ }
+ }
+
+ printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n",
+ mem);
+ BUG();
+}
+
+static void isp1760_init_regs(struct usb_hcd *hcd)
+{
+ isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ISO_PTD_SKIPMAP_REG);
+
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ATL_PTD_DONEMAP_REG);
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_INT_PTD_DONEMAP_REG);
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ISO_PTD_DONEMAP_REG);
+}
+
+static int handshake(struct isp1760_hcd *priv, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = isp1760_readl(ptr);
+ if (result == ~0)
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct isp1760_hcd *priv)
+{
+ int retval;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+ u32 command = isp1760_readl(hcd->regs + HC_USBCMD);
+
+ command |= CMD_RESET;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+ hcd->state = HC_STATE_HALT;
+ priv->next_statechange = jiffies;
+ retval = handshake(priv, hcd->regs + HC_USBCMD,
+ CMD_RESET, 0, 250 * 1000);
+ return retval;
+}
+
+static void qh_destroy(struct isp1760_qh *qh)
+{
+ BUG_ON(!list_empty(&qh->qtd_list));
+ kmem_cache_free(qh_cachep, qh);
+}
+
+static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv,
+ gfp_t flags)
+{
+ struct isp1760_qh *qh;
+
+ qh = kmem_cache_zalloc(qh_cachep, flags);
+ if (!qh)
+ return qh;
+
+ INIT_LIST_HEAD(&qh->qtd_list);
+ qh->priv = priv;
+ return qh;
+}
+
+/* magic numbers that can affect system performance */
+#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+
+/* one-time init, only for memory state */
+static int priv_init(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 hcc_params;
+
+ spin_lock_init(&priv->lock);
+
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+ */
+ priv->periodic_size = DEFAULT_I_TDPS;
+
+ /* controllers may cache some of the periodic schedule ... */
+ hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS);
+ /* full frame cache */
+ if (HCC_ISOC_CACHE(hcc_params))
+ priv->i_thresh = 8;
+ else /* N microframes cached */
+ priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+ return 0;
+}
+
+static int isp1760_hc_setup(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int result;
+ u32 scratch;
+
+ isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG);
+ scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG);
+ if (scratch != 0xdeadbabe) {
+ printk(KERN_ERR "ISP1760: Scratch test failed.\n");
+ return -ENODEV;
+ }
+
+ /* pre reset */
+ isp1760_init_regs(hcd);
+
+ /* reset */
+ isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG);
+ mdelay(100);
+
+ isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG);
+ mdelay(100);
+
+ result = ehci_reset(priv);
+ if (result)
+ return result;
+
+ /* Step 11 passed */
+
+ isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG);
+ isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE);
+
+ /* ATL reset */
+ scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+ isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL);
+ mdelay(10);
+ isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL);
+
+ isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL);
+ mdelay(10);
+
+ priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS);
+
+ return priv_init(hcd);
+}
+
+static void isp1760_init_maps(struct usb_hcd *hcd)
+{
+ /*set last maps, for iso its only 1, else 32 tds bitmap*/
+ isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG);
+ isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG);
+ isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG);
+}
+
+static void isp1760_enable_interrupts(struct usb_hcd *hcd)
+{
+ isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG);
+ isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG);
+ isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG);
+ isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG);
+ /* step 23 passed */
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+ u32 temp;
+ u32 command;
+ u32 chipid;
+
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
+ hcd->state = HC_STATE_RUNNING;
+ isp1760_enable_interrupts(hcd);
+ temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+ temp |= FINAL_HW_CONFIG;
+ isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL);
+
+ command = isp1760_readl(hcd->regs + HC_USBCMD);
+ command &= ~(CMD_LRESET|CMD_RESET);
+ command |= CMD_RUN;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+
+ retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN,
+ 250 * 1000);
+ if (retval)
+ return retval;
+
+ /*
+ * XXX
+ * Spec says to write FLAG_CF as last config action, priv code grabs
+ * the semaphore while doing so.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG);
+
+ retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF,
+ 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG);
+ isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff,
+ chipid >> 16);
+
+ /* PTD Register Init Part 2, Step 28 */
+ /* enable INTs */
+ isp1760_init_maps(hcd);
+
+ /* 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.
+ */
+ return 0;
+}
+
+static u32 base_to_chip(u32 base)
+{
+ return ((base - 0x400) >> 3);
+}
+
+static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ u32 dw0;
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
+ u32 maxpacket;
+ u32 multi;
+ u32 pid_code;
+ u32 rl = RL_COUNTER;
+ u32 nak = NAK_COUNTER;
+
+ /* according to 3.6.2, max packet len can not be > 0x400 */
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+
+ /* DW0 */
+ dw0 = PTD_VALID;
+ dw0 |= PTD_LENGTH(qtd->length);
+ dw0 |= PTD_MAXPACKET(maxpacket);
+ dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe));
+ dw1 = usb_pipeendpoint(urb->pipe) >> 1;
+
+ /* DW1 */
+ dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe));
+
+ pid_code = qtd->packet_type;
+ dw1 |= PTD_PID_TOKEN(pid_code);
+
+ if (usb_pipebulk(urb->pipe))
+ dw1 |= PTD_TRANS_BULK;
+ else if (usb_pipeint(urb->pipe))
+ dw1 |= PTD_TRANS_INT;
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* split transaction */
+
+ dw1 |= PTD_TRANS_SPLIT;
+ if (urb->dev->speed == USB_SPEED_LOW)
+ dw1 |= PTD_SE_USB_LOSPEED;
+
+ dw1 |= PTD_PORT_NUM(urb->dev->ttport);
+ dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum);
+
+ /* SE bit for Split INT transfers */
+ if (usb_pipeint(urb->pipe) &&
+ (urb->dev->speed == USB_SPEED_LOW))
+ dw1 |= 2 << 16;
+
+ dw3 = 0;
+ rl = 0;
+ nak = 0;
+ } else {
+ dw0 |= PTD_MULTI(multi);
+ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe))
+ dw3 = qh->ping;
+ else
+ dw3 = 0;
+ }
+ /* DW2 */
+ dw2 = 0;
+ dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload));
+ dw2 |= PTD_RL_CNT(rl);
+ dw3 |= PTD_NAC_CNT(nak);
+
+ /* DW3 */
+ if (usb_pipecontrol(urb->pipe))
+ dw3 |= PTD_DATA_TOGGLE(qtd->toggle);
+ else
+ dw3 |= qh->toggle;
+
+
+ dw3 |= PTD_ACTIVE;
+ /* Cerr */
+ dw3 |= PTD_CERR(ERR_COUNTER);
+
+ memset(ptd, 0, sizeof(*ptd));
+
+ ptd->dw0 = cpu_to_le32(dw0);
+ ptd->dw1 = cpu_to_le32(dw1);
+ ptd->dw2 = cpu_to_le32(dw2);
+ ptd->dw3 = cpu_to_le32(dw3);
+}
+
+static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ u32 maxpacket;
+ u32 multi;
+ u32 numberofusofs;
+ u32 i;
+ u32 usofmask, usof;
+ u32 period;
+
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+ /* length of the data per uframe */
+ maxpacket = multi * maxpacket;
+
+ numberofusofs = urb->transfer_buffer_length / maxpacket;
+ if (urb->transfer_buffer_length % maxpacket)
+ numberofusofs += 1;
+
+ usofmask = 1;
+ usof = 0;
+ for (i = 0; i < numberofusofs; i++) {
+ usof |= usofmask;
+ usofmask <<= 1;
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* split */
+ ptd->dw5 = __constant_cpu_to_le32(0x1c);
+
+ if (qh->period >= 32)
+ period = qh->period / 2;
+ else
+ period = qh->period;
+
+ } else {
+
+ if (qh->period >= 8)
+ period = qh->period/8;
+ else
+ period = qh->period;
+
+ if (period >= 32)
+ period = 16;
+
+ if (qh->period >= 8) {
+ /* millisecond period */
+ period = (period << 3);
+ } else {
+ /* usof based tranmsfers */
+ /* minimum 4 usofs */
+ usof = 0x11;
+ }
+ }
+
+ ptd->dw2 |= cpu_to_le32(period);
+ ptd->dw4 = cpu_to_le32(usof);
+}
+
+static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ transform_into_atl(priv, qh, qtd, urb, payload, ptd);
+ transform_add_int(priv, qh, qtd, urb, payload, ptd);
+}
+
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len,
+ u32 token)
+{
+ int count;
+
+ qtd->data_buffer = databuffer;
+ qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
+ qtd->toggle = GET_DATA_TOGGLE(token);
+
+ if (len > HC_ATL_PL_SIZE)
+ count = HC_ATL_PL_SIZE;
+ else
+ count = len;
+
+ qtd->length = count;
+ return count;
+}
+
+static int check_error(struct ptd *ptd)
+{
+ int error = 0;
+ u32 dw3;
+
+ dw3 = le32_to_cpu(ptd->dw3);
+ if (dw3 & DW3_HALT_BIT)
+ error = -EPIPE;
+
+ if (dw3 & DW3_ERROR_BIT) {
+ printk(KERN_ERR "error bit is set in DW3\n");
+ error = -EPIPE;
+ }
+
+ if (dw3 & DW3_QTD_ACTIVE) {
+ printk(KERN_ERR "transfer active bit is set DW3\n");
+ printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf,
+ (le32_to_cpu(ptd->dw2) >> 25) & 0xf);
+ }
+
+ return error;
+}
+
+static void check_int_err_status(u32 dw4)
+{
+ u32 i;
+
+ dw4 >>= 8;
+
+ for (i = 0; i < 8; i++) {
+ switch (dw4 & 0x7) {
+ case INT_UNDERRUN:
+ printk(KERN_ERR "ERROR: under run , %d\n", i);
+ break;
+
+ case INT_EXACT:
+ printk(KERN_ERR "ERROR: transaction error, %d\n", i);
+ break;
+
+ case INT_BABBLE:
+ printk(KERN_ERR "ERROR: babble error, %d\n", i);
+ break;
+ }
+ dw4 >>= 3;
+ }
+}
+
+static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv,
+ u32 payload)
+{
+ u32 token;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ token = qtd->packet_type;
+
+ if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) {
+ switch (token) {
+ case IN_PID:
+ break;
+ case OUT_PID:
+ case SETUP_PID:
+ priv_write_copy(priv, qtd->data_buffer,
+ hcd->regs + payload,
+ qtd->length);
+ }
+ }
+}
+
+static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload,
+ struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+ struct ptd ptd;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ transform_into_atl(priv, qh, qtd, urb, payload, &ptd);
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd));
+ enqueue_one_qtd(qtd, priv, payload);
+
+ priv->atl_ints[slot].urb = urb;
+ priv->atl_ints[slot].qh = qh;
+ priv->atl_ints[slot].qtd = qtd;
+ priv->atl_ints[slot].data_buffer = qtd->data_buffer;
+ priv->atl_ints[slot].payload = payload;
+ qtd->status |= URB_ENQUEUED | URB_TYPE_ATL;
+ qtd->status |= slot << 16;
+}
+
+static void enqueue_one_int_qtd(u32 int_regs, u32 payload,
+ struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+ struct ptd ptd;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ transform_into_int(priv, qh, qtd, urb, payload, &ptd);
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd));
+ enqueue_one_qtd(qtd, priv, payload);
+
+ priv->int_ints[slot].urb = urb;
+ priv->int_ints[slot].qh = qh;
+ priv->int_ints[slot].qtd = qtd;
+ priv->int_ints[slot].data_buffer = qtd->data_buffer;
+ priv->int_ints[slot].payload = payload;
+ qtd->status |= URB_ENQUEUED | URB_TYPE_INT;
+ qtd->status |= slot << 16;
+}
+
+void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 skip_map, or_map;
+ u32 queue_entry;
+ u32 slot;
+ u32 atl_regs, payload;
+ u32 buffstatus;
+
+ skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+ BUG_ON(!skip_map);
+ slot = __ffs(skip_map);
+ queue_entry = 1 << slot;
+
+ atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd);
+
+ payload = alloc_mem(priv, qtd->length);
+
+ enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+ or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ or_map |= queue_entry;
+ isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+ skip_map &= ~queue_entry;
+ isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+ buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+ buffstatus |= ATL_BUFFER;
+ isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 skip_map, or_map;
+ u32 queue_entry;
+ u32 slot;
+ u32 int_regs, payload;
+ u32 buffstatus;
+
+ skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+ BUG_ON(!skip_map);
+ slot = __ffs(skip_map);
+ queue_entry = 1 << slot;
+
+ int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd);
+
+ payload = alloc_mem(priv, qtd->length);
+
+ enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+ or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ or_map |= queue_entry;
+ isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+ skip_map &= ~queue_entry;
+ isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+ buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+ buffstatus |= INT_BUFFER;
+ isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+ if (!urb->unlinked) {
+ if (status == -EINPROGRESS)
+ status = 0;
+ }
+
+ /* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+ spin_unlock(&priv->lock);
+ usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status);
+ spin_lock(&priv->lock);
+}
+
+static void isp1760_qtd_free(struct isp1760_qtd *qtd)
+{
+ kmem_cache_free(qtd_cachep, qtd);
+}
+
+static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd)
+{
+ struct isp1760_qtd *tmp_qtd;
+
+ tmp_qtd = qtd->hw_next;
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ return tmp_qtd;
+}
+
+/*
+ * Remove this QTD from the QH list and free its memory. If this QTD
+ * isn't the last one than remove also his successor(s).
+ * Returns the QTD which is part of an new URB and should be enqueued.
+ */
+static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd)
+{
+ struct isp1760_qtd *tmp_qtd;
+ int last_one;
+
+ do {
+ tmp_qtd = qtd->hw_next;
+ last_one = qtd->status & URB_COMPLETE_NOTIFY;
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ qtd = tmp_qtd;
+ } while (!last_one && qtd);
+
+ return qtd;
+}
+
+static void do_atl_int(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 done_map, skip_map;
+ struct ptd ptd;
+ struct urb *urb = NULL;
+ u32 atl_regs_base;
+ u32 atl_regs;
+ u32 queue_entry;
+ u32 payload;
+ u32 length;
+ u32 or_map;
+ u32 status = -EINVAL;
+ int error;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qh *qh;
+ u32 rl;
+ u32 nakcount;
+
+ done_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_DONEMAP_REG);
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+
+ or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ or_map &= ~done_map;
+ isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+ atl_regs_base = ATL_REGS_OFFSET;
+ while (done_map) {
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
+
+ status = 0;
+
+ queue_entry = __ffs(done_map);
+ done_map &= ~(1 << queue_entry);
+ skip_map |= 1 << queue_entry;
+
+ atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd);
+
+ urb = priv->atl_ints[queue_entry].urb;
+ qtd = priv->atl_ints[queue_entry].qtd;
+ qh = priv->atl_ints[queue_entry].qh;
+ payload = priv->atl_ints[queue_entry].payload;
+
+ if (!qh) {
+ printk(KERN_ERR "qh is 0\n");
+ continue;
+ }
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs,
+ atl_regs, sizeof(ptd));
+
+ dw1 = le32_to_cpu(ptd.dw1);
+ dw2 = le32_to_cpu(ptd.dw2);
+ dw3 = le32_to_cpu(ptd.dw3);
+ rl = (dw2 >> 25) & 0x0f;
+ nakcount = (dw3 >> 19) & 0xf;
+
+ /* Transfer Error, *but* active and no HALT -> reload */
+ if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) &&
+ !(dw3 & DW3_HALT_BIT)) {
+
+ /* according to ppriv code, we have to
+ * reload this one if trasfered bytes != requested bytes
+ * else act like everything went smooth..
+ * XXX This just doesn't feel right and hasn't
+ * triggered so far.
+ */
+
+ length = PTD_XFERRED_LENGTH(dw3);
+ printk(KERN_ERR "Should reload now.... transfered %d "
+ "of %zu\n", length, qtd->length);
+ BUG();
+ }
+
+ if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) {
+ u32 buffstatus;
+
+ /* XXX
+ * NAKs are handled in HW by the chip. Usually if the
+ * device is not able to send data fast enough.
+ * This did not trigger for a long time now.
+ */
+ printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: "
+ "%d of %zu done: %08x cur: %08x\n", qtd,
+ urb, qh, PTD_XFERRED_LENGTH(dw3),
+ qtd->length, done_map,
+ (1 << queue_entry));
+
+ /* RL counter = ERR counter */
+ dw3 &= ~(0xf << 19);
+ dw3 |= rl << 19;
+ dw3 &= ~(3 << (55 - 32));
+ dw3 |= ERR_COUNTER << (55 - 32);
+
+ /*
+ * It is not needed to write skip map back because it
+ * is unchanged. Just make sure that this entry is
+ * unskipped once it gets written to the HW.
+ */
+ skip_map &= ~(1 << queue_entry);
+ or_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_IRQ_MASK_OR_REG);
+ or_map |= 1 << queue_entry;
+ isp1760_writel(or_map, usb_hcd->regs +
+ HC_ATL_IRQ_MASK_OR_REG);
+
+ ptd.dw3 = cpu_to_le32(dw3);
+ priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+ atl_regs, sizeof(ptd));
+
+ ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID);
+ priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+ atl_regs, sizeof(ptd));
+
+ buffstatus = isp1760_readl(usb_hcd->regs +
+ HC_BUFFER_STATUS_REG);
+ buffstatus |= ATL_BUFFER;
+ isp1760_writel(buffstatus, usb_hcd->regs +
+ HC_BUFFER_STATUS_REG);
+ continue;
+ }
+
+ error = check_error(&ptd);
+ if (error) {
+ status = error;
+ priv->atl_ints[queue_entry].qh->toggle = 0;
+ priv->atl_ints[queue_entry].qh->ping = 0;
+ urb->status = -EPIPE;
+
+#if 0
+ printk(KERN_ERR "Error in %s().\n", __func__);
+ printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+ "dw3: %08x dw4: %08x dw5: %08x dw6: "
+ "%08x dw7: %08x\n",
+ ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+ ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+ } else {
+ if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+ priv->atl_ints[queue_entry].qh->toggle = dw3 &
+ (1 << 25);
+ priv->atl_ints[queue_entry].qh->ping = dw3 &
+ (1 << 26);
+ }
+ }
+
+ length = PTD_XFERRED_LENGTH(dw3);
+ if (length) {
+ switch (DW1_GET_PID(dw1)) {
+ case IN_PID:
+ priv_read_copy(priv,
+ priv->atl_ints[queue_entry].data_buffer,
+ usb_hcd->regs + payload, payload,
+ length);
+
+ case OUT_PID:
+
+ urb->actual_length += length;
+
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ priv->atl_ints[queue_entry].data_buffer = NULL;
+ priv->atl_ints[queue_entry].urb = NULL;
+ priv->atl_ints[queue_entry].qtd = NULL;
+ priv->atl_ints[queue_entry].qh = NULL;
+
+ free_mem(priv, payload);
+
+ isp1760_writel(skip_map, usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+
+ if (urb->status == -EPIPE) {
+ /* HALT was received */
+
+ qtd = clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) {
+ /* short BULK received */
+
+ printk(KERN_ERR "short bulk, %d instead %zu\n", length,
+ qtd->length);
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ urb->status = -EREMOTEIO;
+ printk(KERN_ERR "not okey\n");
+ }
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_up_qtdlist(qtd);
+
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+ /* that was the last qtd of that URB */
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_this_qtd(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else {
+ /* next QTD of this URB */
+
+ qtd = clean_this_qtd(qtd);
+ BUG_ON(!qtd);
+ }
+
+ if (qtd)
+ enqueue_an_ATL_packet(usb_hcd, qh, qtd);
+
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+ }
+}
+
+static void do_intl_int(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 done_map, skip_map;
+ struct ptd ptd;
+ struct urb *urb = NULL;
+ u32 int_regs;
+ u32 int_regs_base;
+ u32 payload;
+ u32 length;
+ u32 or_map;
+ int error;
+ u32 queue_entry;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qh *qh;
+
+ done_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_DONEMAP_REG);
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+
+ or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ or_map &= ~done_map;
+ isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+ int_regs_base = INT_REGS_OFFSET;
+
+ while (done_map) {
+ u32 dw1;
+ u32 dw3;
+
+ queue_entry = __ffs(done_map);
+ done_map &= ~(1 << queue_entry);
+ skip_map |= 1 << queue_entry;
+
+ int_regs = int_regs_base + queue_entry * sizeof(struct ptd);
+ urb = priv->int_ints[queue_entry].urb;
+ qtd = priv->int_ints[queue_entry].qtd;
+ qh = priv->int_ints[queue_entry].qh;
+ payload = priv->int_ints[queue_entry].payload;
+
+ if (!qh) {
+ printk(KERN_ERR "(INT) qh is 0\n");
+ continue;
+ }
+
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs,
+ int_regs, sizeof(ptd));
+ dw1 = le32_to_cpu(ptd.dw1);
+ dw3 = le32_to_cpu(ptd.dw3);
+ check_int_err_status(le32_to_cpu(ptd.dw4));
+
+ error = check_error(&ptd);
+ if (error) {
+#if 0
+ printk(KERN_ERR "Error in %s().\n", __func__);
+ printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+ "dw3: %08x dw4: %08x dw5: %08x dw6: "
+ "%08x dw7: %08x\n",
+ ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+ ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+ urb->status = -EPIPE;
+ priv->int_ints[queue_entry].qh->toggle = 0;
+ priv->int_ints[queue_entry].qh->ping = 0;
+
+ } else {
+ priv->int_ints[queue_entry].qh->toggle =
+ dw3 & (1 << 25);
+ priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26);
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH)
+ length = PTD_XFERRED_LENGTH_LO(dw3);
+ else
+ length = PTD_XFERRED_LENGTH(dw3);
+
+ if (length) {
+ switch (DW1_GET_PID(dw1)) {
+ case IN_PID:
+ priv_read_copy(priv,
+ priv->int_ints[queue_entry].data_buffer,
+ usb_hcd->regs + payload , payload,
+ length);
+ case OUT_PID:
+
+ urb->actual_length += length;
+
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ priv->int_ints[queue_entry].data_buffer = NULL;
+ priv->int_ints[queue_entry].urb = NULL;
+ priv->int_ints[queue_entry].qtd = NULL;
+ priv->int_ints[queue_entry].qh = NULL;
+
+ isp1760_writel(skip_map, usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ free_mem(priv, payload);
+
+ if (urb->status == -EPIPE) {
+ /* HALT received */
+
+ qtd = clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_this_qtd(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else {
+ /* next QTD of this URB */
+
+ qtd = clean_this_qtd(qtd);
+ BUG_ON(!qtd);
+ }
+
+ if (qtd)
+ enqueue_an_INT_packet(usb_hcd, qh, qtd);
+
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ }
+}
+
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb,
+ gfp_t flags)
+{
+ struct isp1760_qh *qh;
+ int is_input, type;
+
+ qh = isp1760_qh_alloc(priv, flags);
+ if (!qh)
+ return qh;
+
+ /*
+ * init endpoint/device data for this QH
+ */
+ is_input = usb_pipein(urb->pipe);
+ type = usb_pipetype(urb->pipe);
+
+ if (type == PIPE_INTERRUPT) {
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+
+ qh->period = urb->interval >> 3;
+ if (qh->period == 0 && urb->interval != 1) {
+ /* NOTE interval 2 or 4 uframes could work.
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
+ printk(KERN_ERR "intr period %d uframes, NYET!",
+ urb->interval);
+ qh_destroy(qh);
+ return NULL;
+ }
+ } else {
+ qh->period = urb->interval;
+ }
+ }
+
+ /* support for tt scheduling, and access to toggles */
+ qh->dev = urb->dev;
+
+ if (!usb_pipecontrol(urb->pipe))
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
+ 1);
+ return qh;
+}
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv,
+ struct urb *urb, struct list_head *qtd_list, int epnum,
+ void **ptr)
+{
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qtd *prev_qtd;
+
+ qh = (struct isp1760_qh *)*ptr;
+ if (!qh) {
+ /* can't sleep here, we have priv->lock... */
+ qh = qh_make(priv, urb, GFP_ATOMIC);
+ if (!qh)
+ return qh;
+ *ptr = qh;
+ }
+
+ qtd = list_entry(qtd_list->next, struct isp1760_qtd,
+ qtd_list);
+ if (!list_empty(&qh->qtd_list))
+ prev_qtd = list_entry(qh->qtd_list.prev,
+ struct isp1760_qtd, qtd_list);
+ else
+ prev_qtd = NULL;
+
+ list_splice(qtd_list, qh->qtd_list.prev);
+ if (prev_qtd) {
+ BUG_ON(prev_qtd->hw_next);
+ prev_qtd->hw_next = qtd;
+ }
+
+ urb->hcpriv = qh;
+ return qh;
+}
+
+static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb,
+ struct list_head *qtd_list)
+{
+ struct list_head *entry, *temp;
+
+ list_for_each_safe(entry, temp, qtd_list) {
+ struct isp1760_qtd *qtd;
+
+ qtd = list_entry(entry, struct isp1760_qtd, qtd_list);
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ }
+}
+
+static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb,
+ struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
+{
+ struct isp1760_qtd *qtd;
+ int epnum;
+ unsigned long flags;
+ struct isp1760_qh *qh = NULL;
+ int rc;
+ int qh_busy;
+
+ qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
+ epnum = urb->ep->desc.bEndpointAddress;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+ rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb);
+ if (rc)
+ goto done;
+
+ qh = urb->ep->hcpriv;
+ if (qh)
+ qh_busy = !list_empty(&qh->qtd_list);
+ else
+ qh_busy = 0;
+
+ qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ if (!qh) {
+ usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (!qh_busy)
+ p(priv_to_hcd(priv), qh, qtd);
+
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (!qh)
+ qtd_list_free(priv, urb, qtd_list);
+ return rc;
+}
+
+static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv,
+ gfp_t flags)
+{
+ struct isp1760_qtd *qtd;
+
+ qtd = kmem_cache_zalloc(qtd_cachep, flags);
+ if (qtd)
+ INIT_LIST_HEAD(&qtd->qtd_list);
+
+ return qtd;
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv,
+ struct urb *urb, struct list_head *head, gfp_t flags)
+{
+ struct isp1760_qtd *qtd, *qtd_prev;
+ void *buf;
+ int len, maxpacket;
+ int is_input;
+ u32 token;
+
+ /*
+ * URBs map to sequences of QTDs: one logical transaction
+ */
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ return NULL;
+
+ list_add_tail(&qtd->qtd_list, head);
+ qtd->urb = urb;
+ urb->status = -EINPROGRESS;
+
+ token = 0;
+ /* for split transactions, SplitXState initialized to zero */
+
+ len = urb->transfer_buffer_length;
+ is_input = usb_pipein(urb->pipe);
+ if (usb_pipecontrol(urb->pipe)) {
+ /* SETUP pid */
+ qtd_fill(qtd, urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ token | SETUP_PID);
+
+ /* ... and always at least one more pid */
+ token ^= DATA_TOGGLE;
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= IN_PID;
+ }
+
+ /*
+ * data transfer stage: buffer setup
+ */
+ buf = urb->transfer_buffer;
+
+ if (is_input)
+ token |= IN_PID;
+ else
+ token |= OUT_PID;
+
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+ for (;;) {
+ int this_qtd_len;
+
+ if (!buf && len) {
+ /* XXX This looks like usb storage / SCSI bug */
+ printk(KERN_ERR "buf is null, dma is %08lx len is %d\n",
+ (long unsigned)urb->transfer_dma, len);
+ WARN_ON(1);
+ }
+
+ this_qtd_len = qtd_fill(qtd, buf, len, token);
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+ token ^= DATA_TOGGLE;
+
+ if (len <= 0)
+ break;
+
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * bulk ones may need a terminating short packet (zero length).
+ */
+ if (urb->transfer_buffer_length != 0) {
+ int one_more = 0;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ /* "in" <--> "out" */
+ token ^= IN_PID;
+ /* force DATA1 */
+ token |= DATA_TOGGLE;
+ } else if (usb_pipebulk(urb->pipe)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % maxpacket)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* never any data in such packets */
+ qtd_fill(qtd, NULL, 0, token);
+ }
+ }
+
+ qtd->status = URB_COMPLETE_NOTIFY;
+ return head;
+
+cleanup:
+ qtd_list_free(priv, urb, head);
+ return NULL;
+}
+
+static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct list_head qtd_list;
+ packet_enqueue *pe;
+
+ INIT_LIST_HEAD(&qtd_list);
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+
+ if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ pe = enqueue_an_ATL_packet;
+ break;
+
+ case PIPE_INTERRUPT:
+ if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ pe = enqueue_an_INT_packet;
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n");
+ default:
+ return -EPIPE;
+ }
+
+ isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe);
+ return 0;
+}
+
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct inter_packet_info *ints;
+ u32 i;
+ u32 reg_base, or_reg, skip_reg;
+ int flags;
+ struct ptd ptd;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ return -EPIPE;
+ break;
+
+ case PIPE_INTERRUPT:
+ ints = priv->int_ints;
+ reg_base = INT_REGS_OFFSET;
+ or_reg = HC_INT_IRQ_MASK_OR_REG;
+ skip_reg = HC_INT_PTD_SKIPMAP_REG;
+ break;
+
+ default:
+ ints = priv->atl_ints;
+ reg_base = ATL_REGS_OFFSET;
+ or_reg = HC_ATL_IRQ_MASK_OR_REG;
+ skip_reg = HC_ATL_PTD_SKIPMAP_REG;
+ break;
+ }
+
+ memset(&ptd, 0, sizeof(ptd));
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < 32; i++) {
+ if (ints->urb == urb) {
+ u32 skip_map;
+ u32 or_map;
+ struct isp1760_qtd *qtd;
+
+ skip_map = isp1760_readl(hcd->regs + skip_reg);
+ skip_map |= 1 << i;
+ isp1760_writel(skip_map, hcd->regs + skip_reg);
+
+ or_map = isp1760_readl(hcd->regs + or_reg);
+ or_map &= ~(1 << i);
+ isp1760_writel(or_map, hcd->regs + or_reg);
+
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base
+ + i * sizeof(ptd), sizeof(ptd));
+ qtd = ints->qtd;
+
+ clean_up_qtdlist(qtd);
+
+ free_mem(priv, ints->payload);
+
+ ints->urb = NULL;
+ ints->qh = NULL;
+ ints->qtd = NULL;
+ ints->data_buffer = NULL;
+ ints->payload = 0;
+
+ isp1760_urb_done(priv, urb, status);
+ break;
+ }
+ ints++;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 imask;
+ irqreturn_t irqret = IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ if (!(usb_hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+ imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG);
+ if (unlikely(!imask))
+ goto leave;
+
+ isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG);
+ if (imask & HC_ATL_INT)
+ do_atl_int(usb_hcd);
+
+ if (imask & HC_INTL_INT)
+ do_intl_int(usb_hcd);
+
+ irqret = IRQ_HANDLED;
+leave:
+ spin_unlock(&priv->lock);
+ return irqret;
+}
+
+static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 temp, status = 0;
+ u32 mask;
+ int retval = 1;
+ unsigned long flags;
+
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(hcd->state))
+ return 0;
+
+ /* init status to no-changes */
+ buf[0] = 0;
+ mask = PORT_CSC;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ temp = isp1760_readl(hcd->regs + HC_PORTSC1);
+
+ if (temp & PORT_OWNER) {
+ if (temp & PORT_CSC) {
+ temp &= ~PORT_CSC;
+ isp1760_writel(temp, hcd->regs + HC_PORTSC1);
+ goto done;
+ }
+ }
+
+ /*
+ * 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 & mask) != 0
+ || ((temp & PORT_RESUME) != 0
+ && time_after_eq(jiffies,
+ priv->reset_done))) {
+ buf [0] |= 1 << (0 + 1);
+ status = STS_PCD;
+ }
+ /* FIXME autosuspend idle root hubs */
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return status ? retval : 0;
+}
+
+static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+ struct usb_hub_descriptor *desc)
+{
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ /* priv 1.0, 2.3.9 says 20ms max */
+ desc->bPwrOn2PwrGood = 10;
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&desc->bitmap[0], 0, temp);
+ memset(&desc->bitmap[temp], 0xff, temp);
+
+ /* per-port overcurrent reporting */
+ temp = 0x0008;
+ if (HCS_PPC(priv->hcs_params))
+ /* per-port power control */
+ temp |= 0x0001;
+ else
+ /* no power switching */
+ temp |= 0x0002;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct isp1760_hcd *priv, int index,
+ u32 __iomem *status_reg, int port_status)
+{
+ if (!(port_status & PORT_CONNECT))
+ return port_status;
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+
+ printk(KERN_ERR "port %d full speed --> companion\n",
+ index + 1);
+
+ port_status |= PORT_OWNER;
+ port_status &= ~PORT_RWC_BITS;
+ isp1760_writel(port_status, status_reg);
+
+ } else
+ printk(KERN_ERR "port %d high speed\n", index + 1);
+
+ return port_status;
+}
+
+static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u32 __iomem *status_reg = hcd->regs + HC_PORTSC1;
+ u32 temp, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+ * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+ * (track current state ourselves) ... blink for diagnostics,
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = isp1760_readl(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:
+ isp1760_writel(temp & ~PORT_PE, status_reg);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ /* XXX error? */
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ if (temp & PORT_RESET)
+ goto error;
+
+ if (temp & PORT_SUSPEND) {
+ if ((temp & PORT_PE) == 0)
+ goto error;
+ /* resume signaling for 20 msec */
+ temp &= ~(PORT_RWC_BITS);
+ isp1760_writel(temp | PORT_RESUME,
+ status_reg);
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(20);
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ isp1760_writel(temp & ~PORT_POWER, status_reg);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ isp1760_writel(temp | PORT_CSC,
+ status_reg);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ /* XXX error ?*/
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ /* GetPortStatus clears reset */
+ break;
+ default:
+ goto error;
+ }
+ isp1760_readl(hcd->regs + HC_USBCMD);
+ break;
+ case GetHubDescriptor:
+ isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+ buf);
+ break;
+ case GetHubStatus:
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ status = 0;
+ temp = isp1760_readl(status_reg);
+
+ /* wPortChange bits */
+ if (temp & PORT_CSC)
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (temp & PORT_RESUME) {
+ printk(KERN_ERR "Port resume should be skipped.\n");
+
+ /* Remote Wakeup received? */
+ if (!priv->reset_done) {
+ /* resume signaling for 20 msec */
+ priv->reset_done = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&priv_to_hcd(priv)->rh_timer,
+ priv->reset_done);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ priv->reset_done = 0;
+
+ /* stop resume signaling */
+ temp = isp1760_readl(status_reg);
+ isp1760_writel(
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(priv, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ isp1760_err(priv,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET)
+ && time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= 1 << USB_PORT_FEAT_C_RESET;
+ priv->reset_done = 0;
+
+ /* force reset to complete */
+ isp1760_writel(temp & ~PORT_RESET,
+ status_reg);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(priv, status_reg,
+ PORT_RESET, 0, 750);
+ if (retval != 0) {
+ isp1760_err(priv, "port %d reset error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+
+ /* see what we found out */
+ temp = check_reset_complete(priv, wIndex, status_reg,
+ isp1760_readl(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_OWNER)
+ printk(KERN_ERR "Warning: PORT_OWNER is set\n");
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ /* status may be from integrated TT */
+ status |= ehci_port_speed(priv, 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_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
+
+ put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = isp1760_readl(status_reg);
+ if (temp & PORT_OWNER)
+ break;
+
+/* temp &= ~PORT_RWC_BITS; */
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ isp1760_writel(temp | PORT_PE, status_reg);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ if ((temp & PORT_PE) == 0
+ || (temp & PORT_RESET) != 0)
+ goto error;
+
+ isp1760_writel(temp | PORT_SUSPEND, status_reg);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ isp1760_writel(temp | PORT_POWER,
+ status_reg);
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+ && PORT_USB11(temp)) {
+ temp |= PORT_OWNER;
+ } else {
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(50);
+ }
+ isp1760_writel(temp, status_reg);
+ break;
+ default:
+ goto error;
+ }
+ isp1760_readl(hcd->regs + HC_USBCMD);
+ break;
+
+ default:
+error:
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return retval;
+}
+
+static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ u32 flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ qh = ep->hcpriv;
+ if (!qh)
+ goto out;
+
+ ep->hcpriv = NULL;
+ do {
+ /* more than entry might get removed */
+ if (list_empty(&qh->qtd_list))
+ break;
+
+ qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd,
+ qtd_list);
+
+ if (qtd->status & URB_ENQUEUED) {
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET);
+ spin_lock_irqsave(&priv->lock, flags);
+ } else {
+ struct urb *urb;
+
+ urb = qtd->urb;
+ clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, -ECONNRESET);
+ }
+ } while (1);
+
+ qh_destroy(qh);
+ /* remove requests and leak them.
+ * ATL are pretty fast done, INT could take a while...
+ * The latter shoule be removed
+ */
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int isp1760_get_frame(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 fr;
+
+ fr = isp1760_readl(hcd->regs + HC_FRINDEX);
+ return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1760_stop(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
+ NULL, 0);
+ mdelay(20);
+
+ spin_lock_irq(&priv->lock);
+ ehci_reset(priv);
+ /* Disable IRQ */
+ isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+ spin_unlock_irq(&priv->lock);
+
+ isp1760_writel(0, hcd->regs + HC_CONFIGFLAG);
+}
+
+static void isp1760_shutdown(struct usb_hcd *hcd)
+{
+ u32 command;
+
+ isp1760_stop(hcd);
+ isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+
+ command = isp1760_readl(hcd->regs + HC_USBCMD);
+ command &= ~CMD_RUN;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+}
+
+static const struct hc_driver isp1760_hc_driver = {
+ .description = "isp1760-hcd",
+ .product_desc = "NXP ISP1760 USB Host Controller",
+ .hcd_priv_size = sizeof(struct isp1760_hcd),
+ .irq = isp1760_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = isp1760_hc_setup,
+ .start = isp1760_run,
+ .stop = isp1760_stop,
+ .shutdown = isp1760_shutdown,
+ .urb_enqueue = isp1760_urb_enqueue,
+ .urb_dequeue = isp1760_urb_dequeue,
+ .endpoint_disable = isp1760_endpoint_disable,
+ .get_frame_number = isp1760_get_frame,
+ .hub_status_data = isp1760_hub_status_data,
+ .hub_control = isp1760_hub_control,
+};
+
+int __init init_kmem_once(void)
+{
+ qtd_cachep = kmem_cache_create("isp1760_qtd",
+ sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
+ SLAB_MEM_SPREAD, NULL);
+
+ if (!qtd_cachep)
+ return -ENOMEM;
+
+ qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
+ 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+ if (!qh_cachep) {
+ kmem_cache_destroy(qtd_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void deinit_kmem_cache(void)
+{
+ kmem_cache_destroy(qtd_cachep);
+ kmem_cache_destroy(qh_cachep);
+}
+
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+ u64 irqflags, struct device *dev, const char *busname)
+{
+ struct usb_hcd *hcd;
+ struct isp1760_hcd *priv;
+ int ret;
+
+ if (usb_disabled())
+ return ERR_PTR(-ENODEV);
+
+ /* prevent usb-core allocating DMA pages */
+ dev->dma_mask = NULL;
+
+ hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id);
+ if (!hcd)
+ return ERR_PTR(-ENOMEM);
+
+ priv = hcd_to_priv(hcd);
+ init_memory(priv);
+ hcd->regs = ioremap(res_start, res_len);
+ if (!hcd->regs) {
+ ret = -EIO;
+ goto err_put;
+ }
+
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+ goto err_unmap;
+
+ hcd->irq = irq;
+ hcd->rsrc_start = res_start;
+ hcd->rsrc_len = res_len;
+
+ return hcd;
+
+err_unmap:
+ iounmap(hcd->regs);
+
+err_put:
+ usb_put_hcd(hcd);
+
+ return ERR_PTR(ret);
+}
+
+MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
+MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
new file mode 100644
index 000000000000..3d86d0f6b147
--- /dev/null
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -0,0 +1,206 @@
+#ifndef _ISP1760_HCD_H_
+#define _ISP1760_HCD_H_
+
+/* exports for if */
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+ u64 irqflags, struct device *dev, const char *busname);
+int init_kmem_once(void);
+void deinit_kmem_cache(void);
+
+/* EHCI capability registers */
+#define HC_CAPLENGTH 0x00
+#define HC_HCSPARAMS 0x04
+#define HC_HCCPARAMS 0x08
+
+/* EHCI operational registers */
+#define HC_USBCMD 0x20
+#define HC_USBSTS 0x24
+#define HC_FRINDEX 0x2c
+#define HC_CONFIGFLAG 0x60
+#define HC_PORTSC1 0x64
+#define HC_ISO_PTD_DONEMAP_REG 0x130
+#define HC_ISO_PTD_SKIPMAP_REG 0x134
+#define HC_ISO_PTD_LASTPTD_REG 0x138
+#define HC_INT_PTD_DONEMAP_REG 0x140
+#define HC_INT_PTD_SKIPMAP_REG 0x144
+#define HC_INT_PTD_LASTPTD_REG 0x148
+#define HC_ATL_PTD_DONEMAP_REG 0x150
+#define HC_ATL_PTD_SKIPMAP_REG 0x154
+#define HC_ATL_PTD_LASTPTD_REG 0x158
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL 0x300
+#define ALL_ATX_RESET (1 << 31)
+#define HW_DATA_BUS_32BIT (1 << 8)
+#define HW_DACK_POL_HIGH (1 << 6)
+#define HW_DREQ_POL_HIGH (1 << 5)
+#define HW_INTR_HIGH_ACT (1 << 2)
+#define HW_INTR_EDGE_TRIG (1 << 1)
+#define HW_GLOBAL_INTR_EN (1 << 0)
+
+#define HC_CHIP_ID_REG 0x304
+#define HC_SCRATCH_REG 0x308
+
+#define HC_RESET_REG 0x30c
+#define SW_RESET_RESET_HC (1 << 1)
+#define SW_RESET_RESET_ALL (1 << 0)
+
+#define HC_BUFFER_STATUS_REG 0x334
+#define ATL_BUFFER 0x1
+#define INT_BUFFER 0x2
+#define ISO_BUFFER 0x4
+#define BUFFER_MAP 0x7
+
+#define HC_MEMORY_REG 0x33c
+#define HC_PORT1_CTRL 0x374
+#define PORT1_POWER (3 << 3)
+#define PORT1_INIT1 (1 << 7)
+#define PORT1_INIT2 (1 << 23)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG 0x310
+
+#define HC_INTERRUPT_ENABLE 0x314
+#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
+#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT)
+
+#define HC_ISO_INT (1 << 9)
+#define HC_ATL_INT (1 << 8)
+#define HC_INTL_INT (1 << 7)
+#define HC_EOT_INT (1 << 3)
+#define HC_SOT_INT (1 << 1)
+
+#define HC_ISO_IRQ_MASK_OR_REG 0x318
+#define HC_INT_IRQ_MASK_OR_REG 0x31C
+#define HC_ATL_IRQ_MASK_OR_REG 0x320
+#define HC_ISO_IRQ_MASK_AND_REG 0x324
+#define HC_INT_IRQ_MASK_AND_REG 0x328
+#define HC_ATL_IRQ_MASK_AND_REG 0x32C
+
+/* Register sets */
+#define HC_BEGIN_OF_ATL 0x0c00
+#define HC_BEGIN_OF_INT 0x0800
+#define HC_BEGIN_OF_ISO 0x0400
+#define HC_BEGIN_OF_PAYLOAD 0x1000
+
+/* urb state*/
+#define DELETE_URB (0x0008)
+#define NO_TRANSFER_ACTIVE (0xffffffff)
+
+#define ATL_REGS_OFFSET (0xc00)
+#define INT_REGS_OFFSET (0x800)
+
+/* Philips Transfer Descriptor (PTD) */
+struct ptd {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 dw2;
+ __le32 dw3;
+ __le32 dw4;
+ __le32 dw5;
+ __le32 dw6;
+ __le32 dw7;
+};
+
+struct inter_packet_info {
+ void *data_buffer;
+ u32 payload;
+#define PTD_FIRE_NEXT (1 << 0)
+#define PTD_URB_FINISHED (1 << 1)
+ struct urb *urb;
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+};
+
+
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd);
+
+#define isp1760_info(priv, fmt, args...) \
+ dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+#define isp1760_err(priv, fmt, args...) \
+ dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+/* chip memory management */
+struct memory_chunk {
+ unsigned int start;
+ unsigned int size;
+ unsigned int free;
+};
+
+/*
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+ * - 4 blocks @ 8192 bytes
+ */
+
+#define BLOCK_1_NUM 32
+#define BLOCK_2_NUM 20
+#define BLOCK_3_NUM 4
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 8192
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define PAYLOAD_SIZE 0xf000
+
+/* I saw if some reloads if the pointer was negative */
+#define ISP1760_NULL_POINTER (0x400)
+
+/* ATL */
+/* DW0 */
+#define PTD_VALID 1
+#define PTD_LENGTH(x) (((u32) x) << 3)
+#define PTD_MAXPACKET(x) (((u32) x) << 18)
+#define PTD_MULTI(x) (((u32) x) << 29)
+#define PTD_ENDPOINT(x) (((u32) x) << 31)
+/* DW1 */
+#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
+#define PTD_PID_TOKEN(x) (((u32) x) << 10)
+#define PTD_TRANS_BULK ((u32) 2 << 12)
+#define PTD_TRANS_INT ((u32) 3 << 12)
+#define PTD_TRANS_SPLIT ((u32) 1 << 14)
+#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
+#define PTD_PORT_NUM(x) (((u32) x) << 18)
+#define PTD_HUB_NUM(x) (((u32) x) << 25)
+#define PTD_PING(x) (((u32) x) << 26)
+/* DW2 */
+#define PTD_RL_CNT(x) (((u32) x) << 25)
+#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
+#define BASE_ADDR 0x1000
+/* DW3 */
+#define PTD_CERR(x) (((u32) x) << 23)
+#define PTD_NAC_CNT(x) (((u32) x) << 19)
+#define PTD_ACTIVE ((u32) 1 << 31)
+#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
+
+#define DW3_HALT_BIT (1 << 30)
+#define DW3_ERROR_BIT (1 << 28)
+#define DW3_QTD_ACTIVE (1 << 31)
+
+#define INT_UNDERRUN (1 << 2)
+#define INT_BABBLE (1 << 1)
+#define INT_EXACT (1 << 0)
+
+#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
+#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
+#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
+
+#define SETUP_PID (2)
+#define IN_PID (1)
+#define OUT_PID (0)
+#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
+
+#define DATA_TOGGLE (1 << 31)
+#define GET_DATA_TOGGLE(x) ((x) >> 31)
+
+/* Errata 1 */
+#define RL_COUNTER (0)
+#define NAK_COUNTER (0)
+#define ERR_COUNTER (2)
+
+#define HC_ATL_PL_SIZE (8192)
+
+#endif
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
new file mode 100644
index 000000000000..440bf94f0d4c
--- /dev/null
+++ b/drivers/usb/host/isp1760-if.c
@@ -0,0 +1,298 @@
+/*
+ * Glue code for the ISP1760 driver and bus
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/io.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+#ifdef CONFIG_USB_ISP1760_OF
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_OF
+static int of_isp1760_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct usb_hcd *hcd;
+ struct device_node *dp = dev->node;
+ struct resource *res;
+ struct resource memory;
+ struct of_irq oirq;
+ int virq;
+ u64 res_len;
+ int ret;
+
+ ret = of_address_to_resource(dp, 0, &memory);
+ if (ret)
+ return -ENXIO;
+
+ res = request_mem_region(memory.start, memory.end - memory.start + 1,
+ dev->dev.bus_id);
+ if (!res)
+ return -EBUSY;
+
+ res_len = memory.end - memory.start + 1;
+
+ if (of_irq_map_one(dp, 0, &oirq)) {
+ ret = -ENODEV;
+ goto release_reg;
+ }
+
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+
+ hcd = isp1760_register(memory.start, res_len, virq,
+ IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+ if (IS_ERR(hcd)) {
+ ret = PTR_ERR(hcd);
+ goto release_reg;
+ }
+
+ dev_set_drvdata(&dev->dev, hcd);
+ return ret;
+
+release_reg:
+ release_mem_region(memory.start, memory.end - memory.start + 1);
+ return ret;
+}
+
+static int of_isp1760_remove(struct of_device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+static struct of_device_id of_isp1760_match[] = {
+ {
+ .compatible = "nxp,usb-isp1760",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_isp1760_match);
+
+static struct of_platform_driver isp1760_of_driver = {
+ .name = "nxp-isp1760",
+ .match_table = of_isp1760_match,
+ .probe = of_isp1760_probe,
+ .remove = of_isp1760_remove,
+};
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+static u32 nxp_pci_io_base;
+static u32 iolength;
+static u32 pci_mem_phy0;
+static u32 length;
+static u8 *chip_addr;
+static u8 *iobase;
+
+static int __devinit isp1761_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ u8 latency, limit;
+ __u32 reg_data;
+ int retry_count;
+ int length;
+ int status = 1;
+ struct usb_hcd *hcd;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
+
+ if (!dev->irq)
+ return -ENODEV;
+
+ /* Grab the PLX PCI mem maped port start address we need */
+ nxp_pci_io_base = pci_resource_start(dev, 0);
+ iolength = pci_resource_len(dev, 0);
+
+ if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
+ printk(KERN_ERR "request region #1\n");
+ return -EBUSY;
+ }
+
+ iobase = ioremap_nocache(nxp_pci_io_base, iolength);
+ if (!iobase) {
+ printk(KERN_ERR "ioremap #1\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ return -ENOMEM;
+ }
+ /* Grab the PLX PCI shared memory of the ISP 1761 we need */
+ pci_mem_phy0 = pci_resource_start(dev, 3);
+ length = pci_resource_len(dev, 3);
+
+ if (length < 0xffff) {
+ printk(KERN_ERR "memory length for this resource is less than "
+ "required\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ iounmap(iobase);
+ return -ENOMEM;
+ }
+
+ if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+ printk(KERN_ERR "host controller already in use\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ iounmap(iobase);
+ return -EBUSY;
+ }
+
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+ }
+
+ /* Try to check whether we can access Scratch Register of
+ * Host Controller or not. The initial PCI access is retried until
+ * local init for the PCI bridge is completed
+ */
+ retry_count = 20;
+ reg_data = 0;
+ while ((reg_data != 0xFACE) && retry_count) {
+ /*by default host is in 16bit mode, so
+ * io operations at this stage must be 16 bit
+ * */
+ writel(0xface, chip_addr + HC_SCRATCH_REG);
+ udelay(100);
+ reg_data = readl(chip_addr + HC_SCRATCH_REG);
+ retry_count--;
+ }
+
+ /* Host Controller presence is detected by writing to scratch register
+ * and reading back and checking the contents are same or not
+ */
+ if (reg_data != 0xFACE) {
+ err("scratch register mismatch %x", reg_data);
+ goto clean;
+ }
+
+ pci_set_master(dev);
+
+ status = readl(iobase + 0x68);
+ status |= 0x900;
+ writel(status, iobase + 0x68);
+
+ dev->dev.dma_mask = NULL;
+ hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+ IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+ pci_set_drvdata(dev, hcd);
+ if (!hcd)
+ return 0;
+clean:
+ status = -ENODEV;
+ iounmap(iobase);
+ release_mem_region(pci_mem_phy0, length);
+ release_mem_region(nxp_pci_io_base, iolength);
+ return status;
+}
+static void isp1761_pci_remove(struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ pci_disable_device(dev);
+
+ iounmap(iobase);
+ iounmap(chip_addr);
+
+ release_mem_region(nxp_pci_io_base, iolength);
+ release_mem_region(pci_mem_phy0, length);
+}
+
+static void isp1761_pci_shutdown(struct pci_dev *dev)
+{
+ printk(KERN_ERR "ips1761_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1760_plx [] = { {
+ /* handle any USB 2.0 EHCI controller */
+ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
+ .driver_data = 0,
+},
+{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, isp1760_plx);
+
+static struct pci_driver isp1761_pci_driver = {
+ .name = "isp1760",
+ .id_table = isp1760_plx,
+ .probe = isp1761_pci_probe,
+ .remove = isp1761_pci_remove,
+ .shutdown = isp1761_pci_shutdown,
+};
+#endif
+
+static int __init isp1760_init(void)
+{
+ int ret = -ENODEV;
+
+ init_kmem_once();
+
+#ifdef CONFIG_USB_ISP1760_OF
+ ret = of_register_platform_driver(&isp1760_of_driver);
+ if (ret) {
+ deinit_kmem_cache();
+ return ret;
+ }
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+ ret = pci_register_driver(&isp1761_pci_driver);
+ if (ret)
+ goto unreg_of;
+#endif
+ return ret;
+
+#ifdef CONFIG_USB_ISP1760_PCI
+unreg_of:
+#endif
+#ifdef CONFIG_USB_ISP1760_OF
+ of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+ deinit_kmem_cache();
+ return ret;
+}
+module_init(isp1760_init);
+
+static void __exit isp1760_exit(void)
+{
+#ifdef CONFIG_USB_ISP1760_OF
+ of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+ pci_unregister_driver(&isp1761_pci_driver);
+#endif
+ deinit_kmem_cache();
+}
+module_exit(isp1760_exit);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 5be3bb3e6a9d..79a78029f896 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -613,7 +613,7 @@ static void start_hnp(struct ohci_hcd *ohci);
static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
- u32 temp;
+ u32 temp = 0;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
@@ -736,14 +736,14 @@ static int ohci_hub_control (
break;
case GetHubStatus:
temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
- put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
+ put_unaligned_le32(temp, buf);
break;
case GetPortStatus:
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
temp = roothub_portstatus (ohci, wIndex);
- put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
+ put_unaligned_le32(temp, buf);
#ifndef OHCI_VERBOSE_DEBUG
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 77204f001b9a..e899a77dfb83 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -90,7 +90,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *res, *mem;
int retval, irq;
- struct usb_hcd *hcd = 0;
+ struct usb_hcd *hcd = NULL;
irq = retval = platform_get_irq(pdev, 0);
if (retval < 0)
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 3fd7a0c12078..426575247b23 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1506,15 +1506,7 @@ static const char proc_filename[] = "driver/sl811h";
static void create_debug_file(struct sl811 *sl811)
{
- struct proc_dir_entry *pde;
-
- pde = create_proc_entry(proc_filename, 0, NULL);
- if (pde == NULL)
- return;
-
- pde->proc_fops = &proc_ops;
- pde->data = sl811;
- sl811->pde = pde;
+ sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811);
}
static void remove_debug_file(struct sl811 *sl811)
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index d3e0d8aa3980..3a7bfe7a8874 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
return 0;
}
-static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
+static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
{
int port;
const char *sys_info;
@@ -261,27 +261,60 @@ __releases(uhci->lock)
__acquires(uhci->lock)
{
int auto_stop;
- int int_enable, egsm_enable;
+ int int_enable, egsm_enable, wakeup_enable;
struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
dev_dbg(&rhdev->dev, "%s%s\n", __func__,
(auto_stop ? " (auto-stop)" : ""));
- /* Enable resume-detect interrupts if they work.
- * Then enter Global Suspend mode if _it_ works, still configured.
+ /* Start off by assuming Resume-Detect interrupts and EGSM work
+ * and that remote wakeups should be enabled.
*/
egsm_enable = USBCMD_EGSM;
- uhci->working_RD = 1;
+ uhci->RD_enable = 1;
int_enable = USBINTR_RESUME;
- if (remote_wakeup_is_broken(uhci))
- egsm_enable = 0;
- if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
+ wakeup_enable = 1;
+
+ /* In auto-stop mode wakeups must always be detected, but
+ * Resume-Detect interrupts may be prohibited. (In the absence
+ * of CONFIG_PM, they are always disallowed.)
+ */
+ if (auto_stop) {
+ if (!device_may_wakeup(&rhdev->dev))
+ int_enable = 0;
+
+ /* In bus-suspend mode wakeups may be disabled, but if they are
+ * allowed then so are Resume-Detect interrupts.
+ */
+ } else {
#ifdef CONFIG_PM
- (!auto_stop && !rhdev->do_remote_wakeup) ||
+ if (!rhdev->do_remote_wakeup)
+ wakeup_enable = 0;
#endif
- (auto_stop && !device_may_wakeup(&rhdev->dev)))
- uhci->working_RD = int_enable = 0;
+ }
+
+ /* EGSM causes the root hub to echo a 'K' signal (resume) out any
+ * port which requests a remote wakeup. According to the USB spec,
+ * every hub is supposed to do this. But if we are ignoring
+ * remote-wakeup requests anyway then there's no point to it.
+ * We also shouldn't enable EGSM if it's broken.
+ */
+ if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
+ egsm_enable = 0;
+
+ /* If we're ignoring wakeup events then there's no reason to
+ * enable Resume-Detect interrupts. We also shouldn't enable
+ * them if they are broken or disallowed.
+ *
+ * This logic may lead us to enabling RD but not EGSM. The UHCI
+ * spec foolishly says that RD works only when EGSM is on, but
+ * there's no harm in enabling it anyway -- perhaps some chips
+ * will implement it!
+ */
+ if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
+ !int_enable)
+ uhci->RD_enable = int_enable = 0;
outw(int_enable, uhci->io_addr + USBINTR);
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
@@ -308,7 +341,11 @@ __acquires(uhci->lock)
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
- uhci_to_hcd(uhci)->poll_rh = !int_enable;
+
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
uhci_scan_schedule(uhci);
uhci_fsbr_off(uhci);
@@ -344,9 +381,12 @@ __acquires(uhci->lock)
* for 20 ms.
*/
if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+ unsigned egsm;
+
+ /* Keep EGSM on if it was set before */
+ egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
uhci->rh_state = UHCI_RH_RESUMING;
- outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
- uhci->io_addr + USBCMD);
+ outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
@@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
spin_unlock_irq(&uhci->lock);
- if (!uhci->working_RD) {
- /* Suspended root hub needs to be polled */
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd);
}
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 340d6ed3e6e9..7d01c5677f92 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -400,8 +400,9 @@ struct uhci_hcd {
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int dead:1; /* Controller has died */
- unsigned int working_RD:1; /* Suspended root hub doesn't
- need to be polled */
+ unsigned int RD_enable:1; /* Suspended root hub with
+ Resume-Detect interrupts
+ enabled */
unsigned int is_initialized:1; /* Data structure is usable */
unsigned int fsbr_is_on:1; /* FSBR is turned on */
unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 11580e81e2c6..189a9db03509 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -63,9 +63,6 @@
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
-#define USB_VENDOR_ID_MICROCHIP 0x04d8
-#define USB_DEVICE_ID_PICDEM 0x000c
-
#ifdef CONFIG_USB_DYNAMIC_MINORS
#define USB_LD_MINOR_BASE 0
#else
@@ -92,7 +89,6 @@ static struct usb_device_id ld_usb_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
- { USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) },
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
{ } /* Terminating entry */
};
@@ -148,7 +144,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
/* Structure to hold all of our device specific stuff */
struct ld_usb {
- struct semaphore sem; /* locks this structure */
+ struct mutex mutex; /* locks this structure */
struct usb_interface* intf; /* save off the usb interface pointer */
int open_count; /* number of times this port has been opened */
@@ -319,7 +315,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
return -ENODEV;
/* lock this device */
- if (down_interruptible(&dev->sem))
+ if (mutex_lock_interruptible(&dev->mutex))
return -ERESTARTSYS;
/* allow opening only once */
@@ -358,7 +354,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
file->private_data = dev;
unlock_exit:
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
return retval;
}
@@ -378,7 +374,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
goto exit;
}
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -389,7 +385,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
}
if (dev->intf == NULL) {
/* the device was unplugged before the file was released */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */
ld_usb_delete(dev);
goto exit;
@@ -402,7 +398,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
dev->open_count = 0;
unlock_exit:
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -448,7 +444,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
goto exit;
/* lock this object */
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -505,7 +501,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
unlock_exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -528,7 +524,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
goto exit;
/* lock this object */
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -602,7 +598,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
unlock_exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -651,7 +647,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev_err(&intf->dev, "Out of memory\n");
goto exit;
}
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mutex);
spin_lock_init(&dev->rbsl);
dev->intf = intf;
init_waitqueue_head(&dev->read_wait);
@@ -765,15 +761,15 @@ static void ld_usb_disconnect(struct usb_interface *intf)
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
- down(&dev->sem);
+ mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
ld_usb_delete(dev);
} else {
dev->intf = NULL;
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
}
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index a51983854ca0..054dedd28127 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -79,30 +79,10 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
/* set up all urbs so they can be used with either bulk or interrupt */
#define INTERRUPT_RATE 1 /* msec/transfer */
-#define xprintk(tdev,level,fmt,args...) \
- dev_printk(level , &(tdev)->intf->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define ERROR(tdev, fmt, args...) \
+ dev_err(&(tdev)->intf->dev , fmt , ## args)
+#define WARN(tdev, fmt, args...) \
+ dev_warn(&(tdev)->intf->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@@ -236,7 +216,7 @@ static struct urb *simple_alloc_urb (
static unsigned pattern = 0;
module_param (pattern, uint, S_IRUGO);
-// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)");
+MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)");
static inline void simple_fill_buf (struct urb *urb)
{
@@ -257,7 +237,7 @@ static inline void simple_fill_buf (struct urb *urb)
}
}
-static inline int simple_check_buf (struct urb *urb)
+static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
{
unsigned i;
u8 expected;
@@ -285,7 +265,7 @@ static inline int simple_check_buf (struct urb *urb)
}
if (*buf == expected)
continue;
- dbg ("buf[%d] = %d (not %d)", i, *buf, expected);
+ ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected);
return -EINVAL;
}
return 0;
@@ -299,6 +279,7 @@ static void simple_free_urb (struct urb *urb)
}
static int simple_io (
+ struct usbtest_dev *tdev,
struct urb *urb,
int iterations,
int vary,
@@ -324,7 +305,7 @@ static int simple_io (
retval = urb->status;
urb->dev = udev;
if (retval == 0 && usb_pipein (urb->pipe))
- retval = simple_check_buf (urb);
+ retval = simple_check_buf(tdev, urb);
if (vary) {
int len = urb->transfer_buffer_length;
@@ -341,7 +322,7 @@ static int simple_io (
urb->transfer_buffer_length = max;
if (expected != retval)
- dev_dbg (&udev->dev,
+ dev_err(&udev->dev,
"%s failed, iterations left %d, status %d (not %d)\n",
label, iterations, retval, expected);
return retval;
@@ -357,7 +338,7 @@ static int simple_io (
static void free_sglist (struct scatterlist *sg, int nents)
{
unsigned i;
-
+
if (!sg)
return;
for (i = 0; i < nents; i++) {
@@ -415,7 +396,7 @@ alloc_sglist (int nents, int max, int vary)
}
static int perform_sglist (
- struct usb_device *udev,
+ struct usbtest_dev *tdev,
unsigned iterations,
int pipe,
struct usb_sg_request *req,
@@ -423,6 +404,7 @@ static int perform_sglist (
int nents
)
{
+ struct usb_device *udev = testdev_to_usbdev(tdev);
int retval = 0;
while (retval == 0 && iterations-- > 0) {
@@ -431,7 +413,7 @@ static int perform_sglist (
? (INTERRUPT_RATE << 3)
: INTERRUPT_RATE,
sg, nents, 0, GFP_KERNEL);
-
+
if (retval)
break;
usb_sg_wait (req);
@@ -446,7 +428,8 @@ static int perform_sglist (
// failure if retval is as we expected ...
if (retval)
- dbg ("perform_sglist failed, iterations left %d, status %d",
+ ERROR(tdev, "perform_sglist failed, "
+ "iterations left %d, status %d\n",
iterations, retval);
return retval;
}
@@ -505,28 +488,28 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate)
alternate);
}
-static int is_good_config (char *buf, int len)
+static int is_good_config(struct usbtest_dev *tdev, int len)
{
struct usb_config_descriptor *config;
-
+
if (len < sizeof *config)
return 0;
- config = (struct usb_config_descriptor *) buf;
+ config = (struct usb_config_descriptor *) tdev->buf;
switch (config->bDescriptorType) {
case USB_DT_CONFIG:
case USB_DT_OTHER_SPEED_CONFIG:
if (config->bLength != 9) {
- dbg ("bogus config descriptor length");
+ ERROR(tdev, "bogus config descriptor length\n");
return 0;
}
/* this bit 'must be 1' but often isn't */
if (!realworld && !(config->bmAttributes & 0x80)) {
- dbg ("high bit of config attributes not set");
+ ERROR(tdev, "high bit of config attributes not set\n");
return 0;
}
if (config->bmAttributes & 0x1f) { /* reserved == 0 */
- dbg ("reserved config bits set");
+ ERROR(tdev, "reserved config bits set\n");
return 0;
}
break;
@@ -538,7 +521,7 @@ static int is_good_config (char *buf, int len)
return 1;
if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */
return 1;
- dbg ("bogus config descriptor read size");
+ ERROR(tdev, "bogus config descriptor read size\n");
return 0;
}
@@ -571,7 +554,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* 9.2.3 constrains the range here */
alt = iface->altsetting [i].desc.bAlternateSetting;
if (alt < 0 || alt >= iface->num_altsetting) {
- dev_dbg (&iface->dev,
+ dev_err(&iface->dev,
"invalid alt [%d].bAltSetting = %d\n",
i, alt);
}
@@ -583,7 +566,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.10] set_interface */
retval = set_altsetting (dev, alt);
if (retval) {
- dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
+ dev_err(&iface->dev, "can't set_interface = %d, %d\n",
alt, retval);
return retval;
}
@@ -591,7 +574,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.4] get_interface always works */
retval = get_altsetting (dev);
if (retval != alt) {
- dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
+ dev_err(&iface->dev, "get alt should be %d, was %d\n",
alt, retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -611,7 +594,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
USB_DIR_IN | USB_RECIP_DEVICE,
0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
- dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+ dev_err(&iface->dev, "get config --> %d %d (1 %d)\n",
retval, dev->buf[0], expected);
return (retval < 0) ? retval : -EDOM;
}
@@ -621,7 +604,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
dev->buf, sizeof udev->descriptor);
if (retval != sizeof udev->descriptor) {
- dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval);
+ dev_err(&iface->dev, "dev descriptor --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -629,8 +612,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
dev->buf, TBUF_SIZE);
- if (!is_good_config (dev->buf, retval)) {
- dev_dbg (&iface->dev,
+ if (!is_good_config(dev, retval)) {
+ dev_err(&iface->dev,
"config [%d] descriptor --> %d\n",
i, retval);
return (retval < 0) ? retval : -EDOM;
@@ -650,14 +633,14 @@ static int ch9_postconfig (struct usbtest_dev *dev)
sizeof (struct usb_qualifier_descriptor));
if (retval == -EPIPE) {
if (udev->speed == USB_SPEED_HIGH) {
- dev_dbg (&iface->dev,
+ dev_err(&iface->dev,
"hs dev qualifier --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM;
}
/* usb2.0 but not high-speed capable; fine */
} else if (retval != sizeof (struct usb_qualifier_descriptor)) {
- dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);
+ dev_err(&iface->dev, "dev qualifier --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
} else
d = (struct usb_qualifier_descriptor *) dev->buf;
@@ -669,8 +652,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_descriptor (udev,
USB_DT_OTHER_SPEED_CONFIG, i,
dev->buf, TBUF_SIZE);
- if (!is_good_config (dev->buf, retval)) {
- dev_dbg (&iface->dev,
+ if (!is_good_config(dev, retval)) {
+ dev_err(&iface->dev,
"other speed config --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM;
@@ -683,7 +666,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
/* [9.4.5] get_status always works */
retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
if (retval != 2) {
- dev_dbg (&iface->dev, "get dev status --> %d\n", retval);
+ dev_err(&iface->dev, "get dev status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -693,11 +676,11 @@ static int ch9_postconfig (struct usbtest_dev *dev)
retval = usb_get_status (udev, USB_RECIP_INTERFACE,
iface->altsetting [0].desc.bInterfaceNumber, dev->buf);
if (retval != 2) {
- dev_dbg (&iface->dev, "get interface status --> %d\n", retval);
+ dev_err(&iface->dev, "get interface status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
// FIXME get status for each endpoint in the interface
-
+
return 0;
}
@@ -752,8 +735,9 @@ static void ctrl_complete (struct urb *urb)
*/
if (subcase->number > 0) {
if ((subcase->number - ctx->last) != 1) {
- dbg ("subcase %d completed out of order, last %d",
- subcase->number, ctx->last);
+ ERROR(ctx->dev,
+ "subcase %d completed out of order, last %d\n",
+ subcase->number, ctx->last);
status = -EDOM;
ctx->last = subcase->number;
goto error;
@@ -777,7 +761,7 @@ static void ctrl_complete (struct urb *urb)
else if (subcase->number == 12 && status == -EPIPE)
status = 0;
else
- dbg ("subtest %d error, status %d",
+ ERROR(ctx->dev, "subtest %d error, status %d\n",
subcase->number, status);
}
@@ -788,9 +772,12 @@ error:
int i;
ctx->status = status;
- info ("control queue %02x.%02x, err %d, %d left",
+ ERROR(ctx->dev, "control queue %02x.%02x, err %d, "
+ "%d left, subcase %d, len %d/%d\n",
reqp->bRequestType, reqp->bRequest,
- status, ctx->count);
+ status, ctx->count, subcase->number,
+ urb->actual_length,
+ urb->transfer_buffer_length);
/* FIXME this "unlink everything" exit route should
* be a separate test case.
@@ -799,7 +786,8 @@ error:
/* unlink whatever's still pending */
for (i = 1; i < ctx->param->sglen; i++) {
struct urb *u = ctx->urb [
- (i + subcase->number) % ctx->param->sglen];
+ (i + subcase->number)
+ % ctx->param->sglen];
if (u == urb || !u->dev)
continue;
@@ -812,7 +800,8 @@ error:
case -EIDRM:
continue;
default:
- dbg ("urb unlink --> %d", status);
+ ERROR(ctx->dev, "urb unlink --> %d\n",
+ status);
}
}
status = ctx->status;
@@ -822,14 +811,15 @@ error:
/* resubmit if we need to, else mark this as done */
if ((status == 0) && (ctx->pending < ctx->count)) {
if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
- dbg ("can't resubmit ctrl %02x.%02x, err %d",
+ ERROR(ctx->dev,
+ "can't resubmit ctrl %02x.%02x, err %d\n",
reqp->bRequestType, reqp->bRequest, status);
urb->dev = NULL;
} else
ctx->pending++;
} else
urb->dev = NULL;
-
+
/* signal completion when nothing's queued */
if (ctx->pending == 0)
complete (&ctx->complete);
@@ -866,6 +856,11 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
struct urb *u;
struct usb_ctrlrequest req;
struct subcase *reqp;
+
+ /* sign of this variable means:
+ * -: tested code must return this (negative) error code
+ * +: tested code may return this (negative too) error code
+ */
int expected = 0;
/* requests here are mostly expected to succeed on any
@@ -918,11 +913,11 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
// interface == 0
len = sizeof (struct usb_interface_descriptor);
- expected = EPIPE;
+ expected = -EPIPE;
break;
// NOTE: two consecutive stalls in the queue here.
// that tests fault recovery a bit more aggressively.
- case 8: // clear endpoint halt (USUALLY STALLS)
+ case 8: // clear endpoint halt (MAY STALL)
req.bRequest = USB_REQ_CLEAR_FEATURE;
req.bRequestType = USB_RECIP_ENDPOINT;
// wValue 0 == ep halt
@@ -965,7 +960,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
break;
case 14: // short read; try to fill the last packet
req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
- // device descriptor size == 18 bytes
+ /* device descriptor size == 18 bytes */
len = udev->descriptor.bMaxPacketSize0;
switch (len) {
case 8: len = 24; break;
@@ -974,7 +969,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
expected = -EREMOTEIO;
break;
default:
- err ("bogus number of ctrl queue testcases!");
+ ERROR(dev, "bogus number of ctrl queue testcases!\n");
context.status = -EINVAL;
goto cleanup;
}
@@ -1003,7 +998,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
for (i = 0; i < param->sglen; i++) {
context.status = usb_submit_urb (urb [i], GFP_ATOMIC);
if (context.status != 0) {
- dbg ("can't submit urb[%d], status %d",
+ ERROR(dev, "can't submit urb[%d], status %d\n",
i, context.status);
context.count = context.pending;
break;
@@ -1070,7 +1065,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
* due to errors, or is just NAKing requests.
*/
if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) {
- dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);
+ dev_err(&dev->intf->dev, "submit fail %d\n", retval);
return retval;
}
@@ -1087,13 +1082,13 @@ retry:
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
- dev_dbg (&dev->intf->dev, "unlink retry\n");
+ ERROR(dev, "unlink retry\n");
goto retry;
}
} else
usb_kill_urb (urb);
if (!(retval == 0 || retval == -EINPROGRESS)) {
- dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);
+ dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
return retval;
}
@@ -1121,7 +1116,7 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
/*-------------------------------------------------------------------------*/
-static int verify_not_halted (int ep, struct urb *urb)
+static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
u16 status;
@@ -1129,20 +1124,21 @@ static int verify_not_halted (int ep, struct urb *urb)
/* shouldn't look or act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
- dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n",
+ ep, retval);
return retval;
}
if (status != 0) {
- dbg ("ep %02x bogus status: %04x != 0", ep, status);
+ ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, 0, __func__);
+ retval = simple_io(tdev, urb, 1, 0, 0, __func__);
if (retval != 0)
return -EINVAL;
return 0;
}
-static int verify_halted (int ep, struct urb *urb)
+static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
u16 status;
@@ -1150,29 +1146,30 @@ static int verify_halted (int ep, struct urb *urb)
/* should look and act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
- dbg ("ep %02x couldn't get halt status, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
+ ep, retval);
return retval;
}
le16_to_cpus(&status);
if (status != 1) {
- dbg ("ep %02x bogus status: %04x != 1", ep, status);
+ ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, -EPIPE, __func__);
+ retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__);
if (retval != -EPIPE)
return -EINVAL;
- retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
+ retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted");
if (retval != -EPIPE)
return -EINVAL;
return 0;
}
-static int test_halt (int ep, struct urb *urb)
+static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
/* shouldn't look or act halted now */
- retval = verify_not_halted (ep, urb);
+ retval = verify_not_halted(tdev, ep, urb);
if (retval < 0)
return retval;
@@ -1182,20 +1179,20 @@ static int test_halt (int ep, struct urb *urb)
USB_ENDPOINT_HALT, ep,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
- dbg ("ep %02x couldn't set halt, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval);
return retval;
}
- retval = verify_halted (ep, urb);
+ retval = verify_halted(tdev, ep, urb);
if (retval < 0)
return retval;
/* clear halt (tests API + protocol), verify it worked */
retval = usb_clear_halt (urb->dev, urb->pipe);
if (retval < 0) {
- dbg ("ep %02x couldn't clear halt, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
return retval;
}
- retval = verify_not_halted (ep, urb);
+ retval = verify_not_halted(tdev, ep, urb);
if (retval < 0)
return retval;
@@ -1217,7 +1214,7 @@ static int halt_simple (struct usbtest_dev *dev)
if (dev->in_pipe) {
ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;
urb->pipe = dev->in_pipe;
- retval = test_halt (ep, urb);
+ retval = test_halt(dev, ep, urb);
if (retval < 0)
goto done;
}
@@ -1225,7 +1222,7 @@ static int halt_simple (struct usbtest_dev *dev)
if (dev->out_pipe) {
ep = usb_pipeendpoint (dev->out_pipe);
urb->pipe = dev->out_pipe;
- retval = test_halt (ep, urb);
+ retval = test_halt(dev, ep, urb);
}
done:
simple_free_urb (urb);
@@ -1275,7 +1272,7 @@ static int ctrl_out (struct usbtest_dev *dev,
if (retval != len) {
what = "write";
if (retval >= 0) {
- INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+ ERROR(dev, "ctrl_out, wlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
@@ -1289,7 +1286,7 @@ static int ctrl_out (struct usbtest_dev *dev,
if (retval != len) {
what = "read";
if (retval >= 0) {
- INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+ ERROR(dev, "ctrl_out, rlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
@@ -1299,7 +1296,7 @@ static int ctrl_out (struct usbtest_dev *dev,
/* fail if we can't verify */
for (j = 0; j < len; j++) {
if (buf [j] != (u8) (i + j)) {
- INFO (dev, "ctrl_out, byte %d is %d not %d\n",
+ ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
j, buf [j], (u8) i + j);
retval = -EBADMSG;
break;
@@ -1321,7 +1318,7 @@ static int ctrl_out (struct usbtest_dev *dev,
}
if (retval < 0)
- INFO (dev, "ctrl_out %s failed, code %d, count %d\n",
+ ERROR (dev, "ctrl_out %s failed, code %d, count %d\n",
what, retval, i);
kfree (buf);
@@ -1366,7 +1363,7 @@ static void iso_callback (struct urb *urb)
case 0:
goto done;
default:
- dev_dbg (&ctx->dev->intf->dev,
+ dev_err(&ctx->dev->intf->dev,
"iso resubmit err %d\n",
status);
/* FALLTHROUGH */
@@ -1381,7 +1378,7 @@ static void iso_callback (struct urb *urb)
ctx->pending--;
if (ctx->pending == 0) {
if (ctx->errors)
- dev_dbg (&ctx->dev->intf->dev,
+ dev_err(&ctx->dev->intf->dev,
"iso test, %lu errors out of %lu\n",
ctx->errors, ctx->packet_count);
complete (&ctx->done);
@@ -1458,7 +1455,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
memset (urbs, 0, sizeof urbs);
udev = testdev_to_usbdev (dev);
- dev_dbg (&dev->intf->dev,
+ dev_info(&dev->intf->dev,
"... iso period %d %sframes, wMaxPacket %04x\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
@@ -1475,7 +1472,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
urbs [i]->context = &context;
}
packets *= param->iterations;
- dev_dbg (&dev->intf->dev,
+ dev_info(&dev->intf->dev,
"... total %lu msec (%lu packets)\n",
(packets * (1 << (desc->bInterval - 1)))
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
@@ -1537,6 +1534,13 @@ fail:
* except indirectly by consuming USB bandwidth and CPU resources for test
* threads and request completion. But the only way to know that for sure
* is to test when HC queues are in use by many devices.
+ *
+ * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(),
+ * it locks out usbcore in certain code paths. Notably, if you disconnect
+ * the device-under-test, khubd will wait block forever waiting for the
+ * ioctl to complete ... so that usb_disconnect() can abort the pending
+ * urbs and then call usbtest_disconnect(). To abort a test, you're best
+ * off just killing the userspace task and waiting for it to exit.
*/
static int
@@ -1575,7 +1579,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
* altsettings; force a default so most tests don't need to check.
*/
if (dev->info->alt >= 0) {
- int res;
+ int res;
if (intf->altsetting->desc.bInterfaceNumber) {
mutex_unlock(&dev->lock);
@@ -1604,7 +1608,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
switch (param->test_num) {
case 0:
- dev_dbg (&intf->dev, "TEST 0: NOP\n");
+ dev_info(&intf->dev, "TEST 0: NOP\n");
retval = 0;
break;
@@ -1612,7 +1616,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 1:
if (dev->out_pipe == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 1: write %d bytes %u times\n",
param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1621,13 +1625,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = simple_io (urb, param->iterations, 0, 0, "test1");
+ retval = simple_io(dev, urb, param->iterations, 0, 0, "test1");
simple_free_urb (urb);
break;
case 2:
if (dev->in_pipe == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 2: read %d bytes %u times\n",
param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1636,13 +1640,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = simple_io (urb, param->iterations, 0, 0, "test2");
+ retval = simple_io(dev, urb, param->iterations, 0, 0, "test2");
simple_free_urb (urb);
break;
case 3:
if (dev->out_pipe == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 3: write/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1651,14 +1655,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = simple_io (urb, param->iterations, param->vary,
+ retval = simple_io(dev, urb, param->iterations, param->vary,
0, "test3");
simple_free_urb (urb);
break;
case 4:
if (dev->in_pipe == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 4: read/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1667,7 +1671,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = simple_io (urb, param->iterations, param->vary,
+ retval = simple_io(dev, urb, param->iterations, param->vary,
0, "test4");
simple_free_urb (urb);
break;
@@ -1676,7 +1680,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 5:
if (dev->out_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 5: write %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1686,7 +1690,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->out_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
@@ -1694,7 +1698,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 6:
if (dev->in_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 6: read %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1704,14 +1708,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->in_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
case 7:
if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
@@ -1721,14 +1725,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->out_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
case 8:
if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
@@ -1738,7 +1742,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->in_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
@@ -1746,13 +1750,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
/* non-queued sanity tests for control (chapter 9 subset) */
case 9:
retval = 0;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 9: ch9 (subset) control tests, %d times\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = ch9_postconfig (dev);
if (retval)
- dbg ("ch9 subset failed, iterations left %d", i);
+ dev_err(&intf->dev, "ch9 subset failed, "
+ "iterations left %d\n", i);
break;
/* queued control messaging */
@@ -1760,7 +1765,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (param->sglen == 0)
break;
retval = 0;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 10: queue %d control calls, %d times\n",
param->sglen,
param->iterations);
@@ -1772,26 +1777,26 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (dev->in_pipe == 0 || !param->length)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n",
+ dev_info(&intf->dev, "TEST 11: unlink %d reads of %d\n",
param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->in_pipe,
param->length);
if (retval)
- dev_dbg (&intf->dev, "unlink reads failed %d, "
+ dev_err(&intf->dev, "unlink reads failed %d, "
"iterations left %d\n", retval, i);
break;
case 12:
if (dev->out_pipe == 0 || !param->length)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n",
+ dev_info(&intf->dev, "TEST 12: unlink %d writes of %d\n",
param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->out_pipe,
param->length);
if (retval)
- dev_dbg (&intf->dev, "unlink writes failed %d, "
+ dev_err(&intf->dev, "unlink writes failed %d, "
"iterations left %d\n", retval, i);
break;
@@ -1800,24 +1805,24 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (dev->out_pipe == 0 && dev->in_pipe == 0)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n",
+ dev_info(&intf->dev, "TEST 13: set/clear %d halts\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = halt_simple (dev);
-
+
if (retval)
- DBG (dev, "halts failed, iterations left %d\n", i);
+ ERROR(dev, "halts failed, iterations left %d\n", i);
break;
/* control write tests */
case 14:
if (!dev->info->ctrl_out)
break;
- dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
+ dev_info(&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
param->iterations,
realworld ? 1 : 0, param->length,
param->vary);
- retval = ctrl_out (dev, param->iterations,
+ retval = ctrl_out(dev, param->iterations,
param->length, param->vary);
break;
@@ -1825,7 +1830,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 15:
if (dev->out_iso_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 15: write %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1838,7 +1843,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 16:
if (dev->in_iso_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 16: read %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1898,7 +1903,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
return -ENODEV;
if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product)
return -ENODEV;
- dbg ("matched module params, vend=0x%04x prod=0x%04x",
+ dev_info(&intf->dev, "matched module params, "
+ "vend=0x%04x prod=0x%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
}
@@ -1940,7 +1946,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
status = get_endpoints (dev, intf);
if (status < 0) {
- dbg ("couldn't get endpoints, %d\n", status);
+ WARN(dev, "couldn't get endpoints, %d\n",
+ status);
return status;
}
/* may find bulk or ISO pipes */
@@ -2082,21 +2089,9 @@ static struct usbtest_info generic_info = {
};
#endif
-// FIXME remove this
-static struct usbtest_info hact_info = {
- .name = "FX2/hact",
- //.ep_in = 6,
- .ep_out = 2,
- .alt = -1,
-};
-
static struct usb_device_id id_table [] = {
- { USB_DEVICE (0x0547, 0x1002),
- .driver_info = (unsigned long) &hact_info,
- },
-
/*-------------------------------------------------------------*/
/* EZ-USB devices which download firmware to replace (or in our
@@ -2185,7 +2180,7 @@ static int __init usbtest_init (void)
{
#ifdef GENERIC
if (vendor)
- dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);
+ pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product);
#endif
return usb_register (&usbtest_driver);
}
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 2cffec85ee7e..9ba64ccc1359 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -447,6 +447,15 @@ config USB_SERIAL_MOS7840
To compile this driver as a module, choose M here: the
module will be called mos7840. If unsure, choose N.
+config USB_SERIAL_MOTOROLA
+ tristate "USB Motorola Phone modem driver"
+ ---help---
+ Say Y here if you want to use a Motorola phone with a USB
+ connector as a modem link.
+
+ To compile this driver as a module, choose M here: the
+ module will be called moto_modem. If unsure, choose N.
+
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 756859510d8c..17a762ab6769 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
+obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 9b1bb347dc2d..db6f97a93c02 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -147,7 +147,7 @@ static void serial_buf_free(struct circ_buf *cb)
*/
static int serial_buf_data_avail(struct circ_buf *cb)
{
- return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
+ return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
}
/*
@@ -171,7 +171,7 @@ static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
buf += c;
count -= c;
- ret= c;
+ ret = c;
}
return ret;
}
@@ -197,7 +197,7 @@ static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
buf += c;
count -= c;
- ret= c;
+ ret = c;
}
return ret;
}
@@ -208,7 +208,7 @@ static void aircable_send(struct usb_serial_port *port)
{
int count, result;
struct aircable_private *priv = usb_get_serial_port_data(port);
- unsigned char* buf;
+ unsigned char *buf;
__le16 *dbuf;
dbg("%s - port %d", __func__, port->number);
if (port->write_urb_busy)
@@ -229,7 +229,8 @@ static void aircable_send(struct usb_serial_port *port)
buf[1] = TX_HEADER_1;
dbuf = (__le16 *)&buf[2];
*dbuf = cpu_to_le16((u16)count);
- serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
+ serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH,
+ MAX_HCI_FRAMESIZE);
memcpy(port->write_urb->transfer_buffer, buf,
count + HCI_HEADER_LENGTH);
@@ -261,7 +262,7 @@ static void aircable_read(struct work_struct *work)
struct tty_struct *tty;
unsigned char *data;
int count;
- if (priv->rx_flags & THROTTLED){
+ if (priv->rx_flags & THROTTLED) {
if (priv->rx_flags & ACTUALLY_THROTTLED)
schedule_work(&priv->rx_work);
return;
@@ -282,10 +283,10 @@ static void aircable_read(struct work_struct *work)
count = min(64, serial_buf_data_avail(priv->rx_buf));
if (count <= 0)
- return; //We have finished sending everything.
+ return; /* We have finished sending everything. */
tty_prepare_flip_string(tty, &data, count);
- if (!data){
+ if (!data) {
err("%s- kzalloc(%d) failed.", __func__, count);
return;
}
@@ -304,9 +305,10 @@ static void aircable_read(struct work_struct *work)
static int aircable_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
- struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
+ struct usb_host_interface *iface_desc = serial->interface->
+ cur_altsetting;
struct usb_endpoint_descriptor *endpoint;
- int num_bulk_out=0;
+ int num_bulk_out = 0;
int i;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
@@ -325,13 +327,13 @@ static int aircable_probe(struct usb_serial *serial,
return 0;
}
-static int aircable_attach (struct usb_serial *serial)
+static int aircable_attach(struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
struct aircable_private *priv;
priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
- if (!priv){
+ if (!priv) {
err("%s- kmalloc(%Zd) failed.", __func__,
sizeof(struct aircable_private));
return -ENOMEM;
@@ -392,7 +394,7 @@ static int aircable_write(struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev, __func__, count, source);
- if (!count){
+ if (!count) {
dbg("%s - write request of 0 bytes", __func__);
return count;
}
@@ -418,31 +420,31 @@ static void aircable_write_bulk_callback(struct urb *urb)
/* This has been taken from cypress_m8.c cypress_write_int_callback */
switch (status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
- port->write_urb_busy = 0;
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __func__, status);
+ port->write_urb_busy = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __func__);
+ dbg("%s - nonzero write bulk status received: %d",
+ __func__, status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting write urb, error %d\n",
+ __func__, result);
+ else
return;
- default:
- /* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __func__);
- dbg("%s - nonzero write bulk status received: %d",
- __func__, status);
- port->write_urb->transfer_buffer_length = 1;
- port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev,
- "%s - failed resubmitting write urb, error %d\n",
- __func__, result);
- else
- return;
}
port->write_urb_busy = 0;
@@ -472,11 +474,11 @@ static void aircable_read_bulk_callback(struct urb *urb)
dbg("%s - caught -EPROTO, resubmitting the urb",
__func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- aircable_read_bulk_callback, port);
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
@@ -490,7 +492,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
}
usb_serial_debug_data(debug, &port->dev, __func__,
- urb->actual_length,urb->transfer_buffer);
+ urb->actual_length, urb->transfer_buffer);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -507,9 +509,9 @@ static void aircable_read_bulk_callback(struct urb *urb)
no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
- no_packages+=1;
+ no_packages++;
- for (i = 0; i < no_packages ;i++) {
+ for (i = 0; i < no_packages; i++) {
if (remaining > (HCI_COMPLETE_FRAME))
package_length = HCI_COMPLETE_FRAME;
else
@@ -529,7 +531,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
if (port->open_count) {
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
+ port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer,
port->read_urb->transfer_buffer_length,
aircable_read_bulk_callback, port);
@@ -602,7 +604,7 @@ static struct usb_serial_driver aircable_device = {
.unthrottle = aircable_unthrottle,
};
-static int __init aircable_init (void)
+static int __init aircable_init(void)
{
int retval;
retval = usb_serial_register(&aircable_device);
@@ -619,7 +621,7 @@ failed_usb_register:
return retval;
}
-static void __exit aircable_exit (void)
+static void __exit aircable_exit(void)
{
usb_deregister(&aircable_driver);
usb_serial_deregister(&aircable_device);
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 725b6b94c274..0798c14ce787 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -68,8 +68,9 @@ static int airprime_send_setup(struct usb_serial_port *port)
val |= 0x02;
return usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x22, 0x21, val, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
}
return 0;
@@ -90,17 +91,19 @@ static void airprime_read_bulk_callback(struct urb *urb)
__func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
- tty_insert_flip_string (tty, data, urb->actual_length);
- tty_flip_buffer_push (tty);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
}
- result = usb_submit_urb (urb, GFP_ATOMIC);
+ result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
__func__, result);
return;
}
@@ -115,7 +118,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
dbg("%s - port %d", __func__, port->number);
/* free up the transfer buffer, as usb_free_urb() does not do this */
- kfree (urb->transfer_buffer);
+ kfree(urb->transfer_buffer);
if (status)
dbg("%s - nonzero write bulk status received: %d",
@@ -171,7 +174,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
}
usb_fill_bulk_urb(urb, serial->dev,
usb_rcvbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
+ port->bulk_out_endpointAddress),
buffer, buffer_size,
airprime_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_KERNEL);
@@ -183,7 +186,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
__func__, i, port->number, result);
goto errout;
}
- /* remember this urb so we can kill it when the port is closed */
+ /* remember this urb so we can kill it when the
+ port is closed */
priv->read_urbp[i] = urb;
}
@@ -192,22 +196,22 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
goto out;
errout:
- /* some error happened, cancel any submitted urbs and clean up anything that
- got allocated successfully */
+ /* some error happened, cancel any submitted urbs and clean up
+ anything that got allocated successfully */
while (i-- != 0) {
urb = priv->read_urbp[i];
buffer = urb->transfer_buffer;
- usb_kill_urb (urb);
- usb_free_urb (urb);
- kfree (buffer);
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
+ kfree(buffer);
}
out:
return result;
}
-static void airprime_close(struct usb_serial_port *port, struct file * filp)
+static void airprime_close(struct usb_serial_port *port, struct file *filp)
{
struct airprime_private *priv = usb_get_serial_port_data(port);
int i;
@@ -220,16 +224,16 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected)
airprime_send_setup(port);
- mutex_lock(&port->serial->disc_mutex);
+ mutex_unlock(&port->serial->disc_mutex);
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]);
+ usb_kill_urb(priv->read_urbp[i]);
+ kfree(priv->read_urbp[i]->transfer_buffer);
+ usb_free_urb(priv->read_urbp[i]);
}
/* free up private structure */
- kfree (priv);
+ kfree(priv);
usb_set_serial_port_data(port, NULL);
}
@@ -259,10 +263,10 @@ static int airprime_write(struct usb_serial_port *port,
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&port->dev, "no more free urbs\n");
- kfree (buffer);
+ kfree(buffer);
return -ENOMEM;
}
- memcpy (buffer, buf, count);
+ memcpy(buffer, buf, count);
usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
@@ -279,7 +283,7 @@ static int airprime_write(struct usb_serial_port *port,
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
__func__, status);
count = status;
- kfree (buffer);
+ kfree(buffer);
} else {
spin_lock_irqsave(&priv->lock, flags);
++priv->outstanding_urbs;
@@ -287,7 +291,7 @@ static int airprime_write(struct usb_serial_port *port,
}
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
- usb_free_urb (urb);
+ usb_free_urb(urb);
return count;
}
@@ -315,8 +319,10 @@ static int __init airprime_init(void)
{
int retval;
- airprime_device.num_ports =
- (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
+ airprime_device.num_ports = endpoints;
+ if (endpoints < 0 || endpoints >= MAX_BULK_EPS)
+ airprime_device.num_ports = NUM_BULK_EPS;
+
retval = usb_serial_register(&airprime_device);
if (retval)
return retval;
@@ -341,6 +347,7 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled");
module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+MODULE_PARM_DESC(buffer_size,
+ "Size of the transfer buffers in bytes (default 4096)");
module_param(endpoints, int, 0);
MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 599ab2e548a7..77895c8f8f31 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -24,7 +24,7 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
static int debug;
@@ -246,29 +246,29 @@ static void ark3116_set_termios(struct usb_serial_port *port,
baud = tty_get_baud_rate(port->tty);
switch (baud) {
- case 75:
- case 150:
- case 300:
- case 600:
- case 1200:
- case 1800:
- case 2400:
- case 4800:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
- case 230400:
- case 460800:
- /* Report the resulting rate back to the caller */
- tty_encode_baud_rate(port->tty, baud, baud);
- break;
- /* set 9600 as default (if given baudrate is invalid for example) */
- default:
- tty_encode_baud_rate(port->tty, 9600, 9600);
- case 0:
- baud = 9600;
+ case 75:
+ case 150:
+ case 300:
+ case 600:
+ case 1200:
+ case 1800:
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 57600:
+ case 115200:
+ case 230400:
+ case 460800:
+ /* Report the resulting rate back to the caller */
+ tty_encode_baud_rate(port->tty, baud, baud);
+ break;
+ /* set 9600 as default (if given baudrate is invalid for example) */
+ default:
+ tty_encode_baud_rate(port->tty, 9600, 9600);
+ case 0:
+ baud = 9600;
}
/*
@@ -380,19 +380,19 @@ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
switch (cmd) {
case TIOCGSERIAL:
/* XXX: Some of these values are probably wrong. */
- memset(&serstruct, 0, sizeof (serstruct));
+ memset(&serstruct, 0, sizeof(serstruct));
serstruct.type = PORT_16654;
serstruct.line = port->serial->minor;
serstruct.port = port->number;
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
- if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
+ if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
return -EFAULT;
return 0;
case TIOCSSERIAL:
- if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
+ if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
return -EFAULT;
return 0;
default:
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index d947d955bceb..ba28fdc9ccd2 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -130,7 +130,7 @@ static int ch341_get_status(struct usb_device *dev)
return -ENOMEM;
r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
- if ( r < 0)
+ if (r < 0)
goto out;
/* Not having the datasheet for the CH341, we ignore the bytes returned
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index dc0ea08ed231..f5b57b196c5a 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
+ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index d17d1645714f..04a56f300ea6 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1421,8 +1421,7 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
if (port->serial->dev) {
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c7329f43d9c9..5b349ece7247 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -133,6 +133,14 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 6da539ede0ee..504edf8c3a3f 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -40,6 +40,17 @@
/* AlphaMicro Components AMC-232USB01 device */
#define FTDI_AMC232_PID 0xFF00 /* Product Id */
+/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
+/* the VID is the standard ftdi vid (FTDI_VID) */
+#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
+#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
+#define FTDI_SCS_DEVICE_2_PID 0xD012
+#define FTDI_SCS_DEVICE_3_PID 0xD013
+#define FTDI_SCS_DEVICE_4_PID 0xD014
+#define FTDI_SCS_DEVICE_5_PID 0xD015
+#define FTDI_SCS_DEVICE_6_PID 0xD016
+#define FTDI_SCS_DEVICE_7_PID 0xD017
+
/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
#define FTDI_ACTZWAVE_PID 0xF2D0
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 8a217648b250..a01e987c7d32 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -643,7 +643,7 @@ static void read_buf_callback(struct urb *urb)
static int iuu_bulk_write(struct usb_serial_port *port)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int flags;
+ unsigned long flags;
int result;
int i;
char *buf_ptr = port->write_urb->transfer_buffer;
@@ -694,7 +694,7 @@ static void iuu_uart_read_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int flags;
+ unsigned long flags;
int status;
int error = 0;
int len = 0;
@@ -759,7 +759,7 @@ static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
int count)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int flags;
+ unsigned long flags;
dbg("%s - enter", __func__);
if (count > 256)
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 6bcb82d3911a..78f2f6db494d 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1713,7 +1713,7 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
{
struct moschip_port *mos7840_port;
unsigned int mcr;
- unsigned int status;
+ int status;
dbg("%s - port %d", __func__, port->number);
@@ -1740,11 +1740,10 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
mos7840_port->shadowMCR = mcr;
- status = 0;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
if (status < 0) {
dbg("setting MODEM_CONTROL_REGISTER Failed\n");
- return -1;
+ return status;
}
return 0;
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
new file mode 100644
index 000000000000..2e8e05462ef7
--- /dev/null
+++ b/drivers/usb/serial/moto_modem.c
@@ -0,0 +1,70 @@
+/*
+ * Motorola USB Phone driver
+ *
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * {sigh}
+ * Mororola should be using the CDC ACM USB spec, but instead
+ * they try to just "do their own thing"... This driver should handle a
+ * few phones in which a basic "dumb serial connection" is needed to be
+ * able to get a connection through to them.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */
+ { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */
+ { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver moto_driver = {
+ .name = "moto-modem",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver moto_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "moto-modem",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+};
+
+static int __init moto_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&moto_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&moto_driver);
+ if (retval)
+ usb_serial_deregister(&moto_device);
+ return retval;
+}
+
+static void __exit moto_exit(void)
+{
+ usb_deregister(&moto_driver);
+ usb_serial_deregister(&moto_device);
+}
+
+module_init(moto_init);
+module_exit(moto_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e4be2d442b1e..e7e016e60333 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -154,8 +154,6 @@ static int option_send_setup(struct usb_serial_port *port);
#define NOVATELWIRELESS_PRODUCT_MC727 0x4100
#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400
-#define NOVATELWIRELESS_PRODUCT_U727 0x5010
-
/* FUTURE NOVATEL PRODUCTS */
#define NOVATELWIRELESS_PRODUCT_EVDO_1 0x6000
#define NOVATELWIRELESS_PRODUCT_HSPA_1 0x7000
@@ -184,6 +182,9 @@ static int option_send_setup(struct usb_serial_port *port);
#define AXESSTEL_VENDOR_ID 0x1726
#define AXESSTEL_PRODUCT_MV110H 0x1000
+#define ONDA_VENDOR_ID 0x19d2
+#define ONDA_PRODUCT_ET502HS 0x0002
+
#define BANDRICH_VENDOR_ID 0x1A8D
#define BANDRICH_PRODUCT_C100_1 0x1002
#define BANDRICH_PRODUCT_C100_2 0x1003
@@ -269,7 +270,6 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */
- { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel U727 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_1) }, /* Novatel EVDO product */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_1) }, /* Novatel HSPA product */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EMBEDDED_1) }, /* Novatel Embedded product */
@@ -293,14 +293,17 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, 0x8133) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8138) }, /* Dell Wireless 5520 Voda I Mobile Broadband (3G HSDPA) Minicard */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
+ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
+ { USB_DEVICE(0x19d2, 0x0001) }, /* Telstra NextG CDMA */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index a9934a3f9845..0cb0d77dc429 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -296,16 +296,14 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
+ if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
- if (!port->open_count) {
- retval = -EINVAL;
- dbg("%s - port not opened", __func__);
- goto exit;
- }
+ /* open_count is managed under the mutex lock for the tty so cannot
+ drop to zero until after the last close completes */
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
retval = port->serial->type->write(port, buf, count);
@@ -317,61 +315,28 @@ exit:
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
dbg("%s - port %d", __func__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- goto exit;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->write_room(port);
-
-exit:
- return retval;
+ return port->serial->type->write_room(port);
}
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
dbg("%s = port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- goto exit;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->chars_in_buffer(port);
-
-exit:
- return retval;
+ return port->serial->type->chars_in_buffer(port);
}
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg ("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(port);
@@ -380,17 +345,9 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(port);
@@ -401,42 +358,27 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- lock_kernel();
- if (!port)
- goto exit;
-
dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
- /* Caution - port->open_count is BKL protected */
- if (!port->open_count) {
- dbg ("%s - port not open", __func__);
- goto exit;
- }
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->ioctl)
+ if (port->serial->type->ioctl) {
+ lock_kernel();
retval = port->serial->type->ioctl(port, file, cmd, arg);
+ unlock_kernel();
+ }
else
retval = -ENOIOCTLCMD;
-exit:
- unlock_kernel();
return retval;
}
static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(port, old);
@@ -448,24 +390,15 @@ static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- lock_kernel();
- if (!port) {
- unlock_kernel();
- return;
- }
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- unlock_kernel();
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->break_ctl)
+ if (port->serial->type->break_ctl) {
+ lock_kernel();
port->serial->type->break_ctl(port, break_state);
- unlock_kernel();
+ unlock_kernel();
+ }
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
@@ -519,19 +452,11 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return -ENODEV;
- }
-
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(port, file);
-
return -EINVAL;
}
@@ -540,19 +465,11 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return -ENODEV;
- }
-
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(port, file, set, clear);
-
return -EINVAL;
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index e96bf8663ffc..f07e8a4c1f3d 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -673,15 +673,13 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
}
*/
- if (port->tty->driver->flush_buffer)
- port->tty->driver->flush_buffer(port->tty);
+ tty_driver_flush_buffer(port->tty);
tty_ldisc_flush(port->tty);
firm_report_tx_done(port);
firm_close(port);
-printk(KERN_ERR"Before processing rx_urbs_submitted.\n");
/* shutdown our bulk reads and writes */
mutex_lock(&info->deathwarrant);
spin_lock_irq(&info->lock);
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 0f6d234d699b..3d9249632ae1 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -123,7 +123,8 @@ config USB_STORAGE_ALAUDA
config USB_STORAGE_ONETOUCH
bool "Support OneTouch Button on Maxtor Hard Drives"
- depends on USB_STORAGE && INPUT_EVDEV
+ depends on USB_STORAGE
+ depends on INPUT=y || INPUT=USB_STORAGE
help
Say Y here to include additional code to support the Maxtor OneTouch
USB hard drive's onetouch button.
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index d88824b3511c..898e67d30e56 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -46,7 +46,7 @@ void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
}
memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
- memset(srb->cmnd, 0, sizeof(srb->cmnd));
+ memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
/* check if we support the command */
if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 971d13dd5e65..3addcd8f827b 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -292,6 +292,7 @@ struct isd200_info {
/* maximum number of LUNs supported */
unsigned char MaxLUNs;
+ unsigned char cmnd[BLK_MAX_CDB];
struct scsi_cmnd srb;
struct scatterlist sg;
};
@@ -450,6 +451,7 @@ static int isd200_action( struct us_data *us, int action,
memset(&ata, 0, sizeof(ata));
memset(&srb_dev, 0, sizeof(srb_dev));
+ srb->cmnd = info->cmnd;
srb->device = &srb_dev;
++srb->serial_number;
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index a28d49122e7a..d617e8ae6b00 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -135,7 +135,7 @@ static int usu_probe(struct usb_interface *intf,
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
- task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
+ task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
if (IS_ERR(task)) {
rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index dfd42fe9e5f0..98b89ea9e312 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -38,7 +38,7 @@
#include "onetouch.h"
#include "debug.h"
-void onetouch_release_input(void *onetouch_);
+static void onetouch_release_input(void *onetouch_);
struct usb_onetouch {
char name[128];
@@ -223,7 +223,7 @@ int onetouch_connect_input(struct us_data *ss)
return error;
}
-void onetouch_release_input(void *onetouch_)
+static void onetouch_release_input(void *onetouch_)
{
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 732bf52a775e..1b09578cbb10 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -44,7 +44,8 @@
* running with this patch.
* Send your submission to either Phil Dibowitz <phil@ipom.com> or
* Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
- * USB development list <linux-usb-devel@lists.sourceforge.net>.
+ * USB development list <linux-usb@vger.kernel.org> and the USB storage list
+ * <usb-storage@lists.one-eyed-alien.net>
*/
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
@@ -400,6 +401,14 @@ UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999,
+ "Cypress",
+ "Cypress AT2LP",
+ US_SC_CYP_ATACB, US_PR_BULK, NULL,
+ 0),
+#endif
+
/* Reported by Simon Levitt <simon@whattf.com>
* This entry needs Sub and Proto fields */
UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100,
@@ -538,25 +547,31 @@ UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
"CD-RW Device",
US_SC_8020, US_PR_CB, NULL, 0),
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
+ "Shuttle/SCM",
+ "USBAT-02",
+ US_SC_SCSI, US_PR_USBAT, init_usbat_flash,
+ US_FL_SINGLE_LUN),
+#endif
+
+/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
+UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
+ "Samsung",
+ "YP-U3",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Device uses standards-violating 32-byte Bulk Command Block Wrappers and
* reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
*/
-
UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100,
"Kobian Mercury",
"Binocam DCB-132",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_BULK32),
-#ifdef CONFIG_USB_STORAGE_USBAT
-UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
- "Shuttle/SCM",
- "USBAT-02",
- US_SC_SCSI, US_PR_USBAT, init_usbat_flash,
- US_FL_SINGLE_LUN),
-#endif
-
/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
"Belkin",
@@ -1200,6 +1215,17 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_BULK32),
+/* Andrew Lunn <andrew@lunn.ch>
+ * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
+ * on LUN 4.
+ * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
+*/
+UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
+ "PanDigital",
+ "Photo Frame",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE),
+
/* Submitted by Jan De Luyck <lkml@kcore.org> */
UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
"CITIZEN",
@@ -1285,6 +1311,16 @@ UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_DEVICE ),
+/* Reported by F. Aben <f.aben@option.com>
+ * This device (wrongly) has a vendor-specific device descriptor.
+ * The entry is needed so usb-storage can bind to it's mass-storage
+ * interface as an interface driver */
+UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
+ "Option",
+ "GI 0401 SD-Card",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0 ),
+
#ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
"ATI",
@@ -1658,6 +1694,16 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Mauro Andreolini <andreoli@weblab.ing.unimo.it>
+ * This entry is needed to bypass the ZeroCD mechanism
+ * and to properly load as a modem device.
+ */
+UNUSUAL_DEV( 0x19d2, 0x2000, 0x0000, 0x0000,
+ "Onda ET502HS",
+ "USB MMC Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE),
+
/* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
* and Renato Perini <rperini@email.it>
*/
@@ -1695,6 +1741,13 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW ),
+/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
+UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
+ "INTOVA",
+ "Pixtreme",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/*
* David Härdeman <david@2gen.com>
* The key makes the SCSI stack print confusing (but harmless) messages
@@ -1719,14 +1772,6 @@ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_CAPACITY_HEURISTICS),
-#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
-UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999,
- "Cypress",
- "Cypress AT2LP",
- US_SC_CYP_ATACB, US_PR_BULK, NULL,
- 0),
-#endif
-
/* Control/Bulk transport for all SubClass values */
USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index a856effad3bd..e268aacb773a 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -539,7 +539,8 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
" has %s in unusual_devs.h (kernel"
" %s)\n"
" Please send a copy of this message to "
- "<linux-usb-devel@lists.sourceforge.net>\n",
+ "<linux-usb@vger.kernel.org> and "
+ "<usb-storage@lists.one-eyed-alien.net>\n",
le16_to_cpu(ddesc->idVendor),
le16_to_cpu(ddesc->idProduct),
le16_to_cpu(ddesc->bcdDevice),
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a576dc261732..002b61b4f0f6 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -171,7 +171,6 @@ config FB_SYS_FOPS
config FB_DEFERRED_IO
bool
depends on FB
- default y
config FB_METRONOME
tristate
@@ -628,11 +627,9 @@ config FB_MAC
select FB_CFB_IMAGEBLIT
select FB_MACMODES
-# bool ' Apple DAFB display support' CONFIG_FB_DAFB
config FB_HP300
bool
- depends on (FB = y) && HP300
- select FB_CFB_FILLRECT
+ depends on (FB = y) && DIO
select FB_CFB_IMAGEBLIT
default y
@@ -1774,6 +1771,11 @@ config FB_PXA
If unsure, say N.
+config FB_PXA_SMARTPANEL
+ bool "PXA Smartpanel LCD support"
+ default n
+ depends on FB_PXA
+
config FB_PXA_PARAMETERS
bool "PXA LCD command line parameters"
default n
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index e6492c1048bf..05a328c11a8b 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -2261,7 +2261,7 @@ int __init amifb_init(void)
amifb_setup(option);
#endif
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
- return -ENXIO;
+ return -ENODEV;
/*
* We request all registers starting from bplpt[0]
@@ -2333,7 +2333,7 @@ default_chipset:
strcat(fb_info.fix.id, "Unknown");
goto default_chipset;
#else /* CONFIG_FB_AMIGA_OCS */
- err = -ENXIO;
+ err = -ENODEV;
goto amifb_error;
#endif /* CONFIG_FB_AMIGA_OCS */
break;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 8ffdf3578768..b004036d4087 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -441,14 +441,15 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
- value = (value / 2) - 1;
- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value);
-
- if (value <= 0) {
+ if (value < 2) {
dev_notice(info->device, "Bypassing pixel clock divider\n");
lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
} else {
- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+ value = (value / 2) - 1;
+ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+ value);
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+ value << ATMEL_LCDC_CLKVAL_OFFSET);
info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
dev_dbg(info->device, " updated pixclk: %lu KHz\n",
PICOS2KHZ(info->var.pixclock));
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 275d9dab0c61..e721644bad74 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -17,11 +17,9 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -299,7 +297,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
par->physbase = op->resource[0].start;
par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&info->var, dp->node, 1);
+ sbusfb_fill_var(&info->var, dp, 1);
linebytes = of_getintprop_default(dp, "linebytes",
info->var.xres);
@@ -329,7 +327,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
if (!info->screen_base)
goto out_unmap_regs;
- bw2_blank(0, info);
+ bw2_blank(FB_BLANK_UNBLANK, info);
bw2_init_fix(info, linebytes);
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index 0db0fecba93b..b17e74671779 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -17,10 +17,9 @@
#include <linux/fb.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -482,7 +481,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
spin_lock_init(&par->lock);
- sbusfb_fill_var(&info->var, dp->node, 8);
+ sbusfb_fill_var(&info->var, dp, 8);
info->var.red.length = 8;
info->var.green.length = 8;
info->var.blue.length = 8;
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 010ea53978f8..3aa7b6cb0268 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -17,11 +17,9 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -373,7 +371,7 @@ static int __devinit cg3_probe(struct of_device *op,
par->physbase = op->resource[0].start;
par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&info->var, dp->node, 8);
+ sbusfb_fill_var(&info->var, dp, 8);
info->var.red.length = 8;
info->var.green.length = 8;
info->var.blue.length = 8;
@@ -398,7 +396,7 @@ static int __devinit cg3_probe(struct of_device *op,
if (!info->screen_base)
goto out_unmap_regs;
- cg3_blank(0, info);
+ cg3_blank(FB_BLANK_UNBLANK, info);
if (!of_find_property(dp, "width", NULL)) {
err = cg3_do_default_mode(par);
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index fc90db6da65a..2f64bb3bd254 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -17,9 +17,9 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -728,7 +728,7 @@ static int __devinit cg6_probe(struct of_device *op,
par->physbase = op->resource[0].start;
par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&info->var, dp->node, 8);
+ sbusfb_fill_var(&info->var, dp, 8);
info->var.red.length = 8;
info->var.green.length = 8;
info->var.blue.length = 8;
@@ -767,7 +767,7 @@ static int __devinit cg6_probe(struct of_device *op,
cg6_bt_init(par);
cg6_chip_init(info);
- cg6_blank(0, info);
+ cg6_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_regs;
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 17b5267f44d7..9f8a389dc7ae 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -381,7 +381,7 @@ int __init clps711xfb_init(void)
/* Register the /proc entries. */
clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
- &proc_root);
+ NULL);
if (clps7111fb_backlight_proc_entry == NULL) {
printk("Couldn't create the /proc entry for the backlight.\n");
return -EINVAL;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 8eda7b60df8f..5fa8b76673cb 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1853,6 +1853,8 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num];
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
+ unsigned short saved_ec;
+ int ret;
if (fbcon_is_inactive(vc, info))
return -EINVAL;
@@ -1865,6 +1867,11 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
* whole screen (prevents flicker).
*/
+ saved_ec = vc->vc_video_erase_char;
+ vc->vc_video_erase_char = vc->vc_scrl_erase_char;
+
+ ret = 0;
+
switch (dir) {
case SM_UP:
if (count > vc->vc_rows) /* Maximum realistic size */
@@ -1881,9 +1888,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
- return 1;
+ ret = 1;
break;
case SCROLL_WRAP_MOVE:
@@ -1953,9 +1960,10 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
- return 1;
+ ret = 1;
+ break;
}
break;
@@ -1972,9 +1980,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
- return 1;
+ ret = 1;
break;
case SCROLL_WRAP_MOVE:
@@ -2042,12 +2050,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
- return 1;
+ ret = 1;
+ break;
}
+ break;
}
- return 0;
+ vc->vc_video_erase_char = saved_ec;
+ return ret;
}
@@ -2507,6 +2518,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
c = vc->vc_video_erase_char;
vc->vc_video_erase_char =
((c & 0xfe00) >> 1) | (c & 0xff);
+ c = vc->vc_def_color;
+ vc->vc_scrl_erase_char =
+ ((c & 0xFE00) >> 1) | (c & 0xFF);
vc->vc_attr >>= 1;
}
} else if (!vc->vc_hi_font_mask && cnt == 512) {
@@ -2537,9 +2551,14 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
if (vc->vc_can_do_color) {
vc->vc_video_erase_char =
((c & 0xff00) << 1) | (c & 0xff);
+ c = vc->vc_def_color;
+ vc->vc_scrl_erase_char =
+ ((c & 0xFF00) << 1) | (c & 0xFF);
vc->vc_attr <<= 1;
- } else
+ } else {
vc->vc_video_erase_char = c & ~0x100;
+ vc->vc_scrl_erase_char = c & ~0x100;
+ }
}
}
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index bd8d995fe25d..38a296bbdfc9 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -531,7 +531,7 @@ static void mdacon_cursor(struct vc_data *c, int mode)
static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
{
- u16 eattr = mda_convert_attr(c->vc_video_erase_char);
+ u16 eattr = mda_convert_attr(c->vc_scrl_erase_char);
if (!lines)
return 0;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 67a682d6cc7b..a11cc2fdd4cd 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
switch (dir) {
case SM_UP:
sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+ sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
break;
case SM_DOWN:
sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+ sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
break;
}
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 6df29a62d720..bd1f57b259d9 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1350,7 +1350,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
} else
c->vc_origin += delta;
scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
- delta), c->vc_video_erase_char,
+ delta), c->vc_scrl_erase_char,
delta);
} else {
if (oldo - delta < vga_vram_base) {
@@ -1363,7 +1363,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
} else
c->vc_origin -= delta;
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
- scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
+ scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char,
delta);
}
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index b083ea7e9c69..606da043f4b4 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -284,6 +284,9 @@ int __init dnfb_init(void)
{
int ret;
+ if (!MACH_IS_APOLLO)
+ return -ENODEV;
+
if (fb_get_options("dnfb", NULL))
return -ENODEV;
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 93dca3e2aa50..7992b13ee68f 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -16,11 +16,10 @@
#include <linux/fb.h>
#include <linux/mm.h>
#include <linux/timer.h>
+#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/upa.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -941,7 +940,7 @@ static int __devinit ffb_probe(struct of_device *op,
info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;
info->pseudo_palette = par->pseudo_palette;
- sbusfb_fill_var(&info->var, dp->node, 32);
+ sbusfb_fill_var(&info->var, dp, 32);
par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);
ffb_fixup_var_rgb(&info->var);
@@ -987,7 +986,7 @@ static int __devinit ffb_probe(struct of_device *op,
* chosen console, it will have video outputs off in
* the DAC.
*/
- ffb_blank(0, info);
+ ffb_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_dac;
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
index cd9d4cc26954..aaef9165ec9b 100644
--- a/drivers/video/geode/lxfb_ops.c
+++ b/drivers/video/geode/lxfb_ops.c
@@ -63,54 +63,32 @@ static const struct {
{ 0x00014284, 19688 },
{ 0x00011104, 20400 },
{ 0x00016363, 23625 },
- { 0x00015303, 24380 },
{ 0x000031AC, 24923 },
{ 0x0000215D, 25175 },
{ 0x00001087, 27000 },
{ 0x0000216C, 28322 },
{ 0x0000218D, 28560 },
- { 0x00010041, 29913 },
{ 0x000010C9, 31200 },
{ 0x00003147, 31500 },
- { 0x000141A1, 32400 },
{ 0x000010A7, 33032 },
- { 0x00012182, 33375 },
- { 0x000141B1, 33750 },
{ 0x00002159, 35112 },
{ 0x00004249, 35500 },
{ 0x00000057, 36000 },
- { 0x000141E1, 37125 },
{ 0x0000219A, 37889 },
{ 0x00002158, 39168 },
{ 0x00000045, 40000 },
- { 0x000131A1, 40500 },
- { 0x00010061, 42301 },
{ 0x00000089, 43163 },
- { 0x00012151, 43875 },
{ 0x000010E7, 44900 },
{ 0x00002136, 45720 },
- { 0x000152E1, 47250 },
- { 0x00010071, 48000 },
{ 0x00003207, 49500 },
{ 0x00002187, 50000 },
- { 0x00014291, 50625 },
- { 0x00011101, 51188 },
- { 0x00017481, 54563 },
{ 0x00004286, 56250 },
- { 0x00014170, 57375 },
- { 0x00016210, 58500 },
{ 0x000010E5, 60065 },
- { 0x00013140, 62796 },
{ 0x00004214, 65000 },
- { 0x00016250, 65250 },
{ 0x00001105, 68179 },
- { 0x000141C0, 69600 },
- { 0x00015220, 70160 },
- { 0x00010050, 72000 },
{ 0x000031E4, 74250 },
{ 0x00003183, 75000 },
{ 0x00004284, 78750 },
- { 0x00012130, 80052 },
{ 0x00001104, 81600 },
{ 0x00006363, 94500 },
{ 0x00005303, 97520 },
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index 2eb4fb159084..b8ebff1e8493 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -382,7 +382,7 @@ int __init hpfb_init(void)
#define INTFBPADDR 0x560000
if (!MACH_IS_HP300)
- return -ENXIO;
+ return -ENODEV;
if (fb_get_options("hpfb", NULL))
return -ENODEV;
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index f3160fc29795..8bc46e930340 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -16,10 +16,9 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -562,7 +561,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id *
par->physbase = op->resource[0].start;
par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&info->var, dp->node, 32);
+ sbusfb_fill_var(&info->var, dp, 32);
leo_fixup_var_rgb(&info->var);
linebytes = of_getintprop_default(dp, "linebytes",
@@ -601,7 +600,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id *
leo_init_wids(info);
leo_init_hw(info);
- leo_blank(0, info);
+ leo_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_regs;
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 9de1c114f809..39ac49e0682c 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -27,6 +27,16 @@ config LOGO_LINUX_CLUT224
bool "Standard 224-color Linux logo"
default y
+config LOGO_BLACKFIN_VGA16
+ bool "16-colour Blackfin Processor Linux logo"
+ depends on BLACKFIN
+ default y
+
+config LOGO_BLACKFIN_CLUT224
+ bool "224-colour Blackfin Processor Linux logo"
+ depends on BLACKFIN
+ default y
+
config LOGO_DEC_CLUT224
bool "224-color Digital Equipment Corporation Linux logo"
depends on MACH_DECSTATION || ALPHA
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index a5fc4edf84e6..b91251d1fe41 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -4,6 +4,8 @@ obj-$(CONFIG_LOGO) += logo.o
obj-$(CONFIG_LOGO_LINUX_MONO) += logo_linux_mono.o
obj-$(CONFIG_LOGO_LINUX_VGA16) += logo_linux_vga16.o
obj-$(CONFIG_LOGO_LINUX_CLUT224) += logo_linux_clut224.o
+obj-$(CONFIG_LOGO_BLACKFIN_CLUT224) += logo_blackfin_clut224.o
+obj-$(CONFIG_LOGO_BLACKFIN_VGA16) += logo_blackfin_vga16.o
obj-$(CONFIG_LOGO_DEC_CLUT224) += logo_dec_clut224.o
obj-$(CONFIG_LOGO_MAC_CLUT224) += logo_mac_clut224.o
obj-$(CONFIG_LOGO_PARISC_CLUT224) += logo_parisc_clut224.o
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index fc72684aae5a..2e85a2b52d05 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -24,6 +24,8 @@
extern const struct linux_logo logo_linux_mono;
extern const struct linux_logo logo_linux_vga16;
extern const struct linux_logo logo_linux_clut224;
+extern const struct linux_logo logo_blackfin_vga16;
+extern const struct linux_logo logo_blackfin_clut224;
extern const struct linux_logo logo_dec_clut224;
extern const struct linux_logo logo_mac_clut224;
extern const struct linux_logo logo_parisc_clut224;
@@ -65,6 +67,10 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
/* Generic Linux logo */
logo = &logo_linux_vga16;
#endif
+#ifdef CONFIG_LOGO_BLACKFIN_VGA16
+ /* Blackfin processor logo */
+ logo = &logo_blackfin_vga16;
+#endif
#ifdef CONFIG_LOGO_SUPERH_VGA16
/* SuperH Linux logo */
logo = &logo_superh_vga16;
@@ -76,6 +82,10 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
/* Generic Linux logo */
logo = &logo_linux_clut224;
#endif
+#ifdef CONFIG_LOGO_BLACKFIN_CLUT224
+ /* Blackfin Linux logo */
+ logo = &logo_blackfin_clut224;
+#endif
#ifdef CONFIG_LOGO_DEC_CLUT224
/* DEC Linux logo on MIPS/MIPS64 or ALPHA */
logo = &logo_dec_clut224;
diff --git a/drivers/video/logo/logo_blackfin_clut224.ppm b/drivers/video/logo/logo_blackfin_clut224.ppm
new file mode 100644
index 000000000000..dc9a50a14477
--- /dev/null
+++ b/drivers/video/logo/logo_blackfin_clut224.ppm
@@ -0,0 +1,1127 @@
+P3
+# This was generated by the GIMP & Netpbm tools
+# gimp linux_bf.svg (create 80x80 save as linux_bf.ppm)
+# pnmquant 224 linux_bf.ppm | pnmnoraw > logo_blackfin_clut224.ppm
+#
+80 80
+255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+1 1 1 3 3 3 4 6 6 6 6 6 4 6 6 3 3 3
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 2 2 2 10 10 10 26 26 27
+44 44 45 66 66 66 78 81 81 78 81 81 75 75 76 60 60 60
+39 39 39 20 20 20 6 6 6 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 2 2 2 14 14 14 47 47 47 84 84 84 75 75 76
+47 47 47 12 12 12 0 0 0 0 0 0 0 0 0 20 20 20
+53 54 54 81 81 82 74 74 74 31 31 31 6 6 6 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+4 4 4 34 34 35 84 84 84 60 60 60 4 4 4 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 17 18 18 75 75 76 66 66 66 17 18 18
+1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3
+42 42 43 84 84 84 8 8 8 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 3 3 36 40 40 10 16 16 0 0 0 31 31 31 84 84 84
+29 29 30 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 26 27 27
+84 84 84 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+15 19 19 114 115 115 110 114 114 44 46 46 0 0 0 12 12 12
+90 87 86 24 24 24 1 1 1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 75 75 76
+14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+30 40 40 133 133 133 129 130 130 78 85 85 23 31 30 0 0 0
+19 19 19 78 81 81 13 13 13 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 26 27 27 81 81 82
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+36 40 40 89 90 91 55 63 63 23 31 30 4 6 6 0 0 0
+0 0 0 60 60 60 47 47 47 2 2 2 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 2 2 2 53 54 54 34 34 35
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+4 10 10 7 9 9 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 84 84 84 13 13 13 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 4 6 6 78 81 81 2 2 2
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 65 64 64 36 36 36 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 10 11 11 81 81 82 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 12 12 12 67 70 70 4 4 4 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 16 16 16 81 81 82 0 0 0
+0 0 0 0 0 0 4 10 10 44 50 50 18 21 21 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 78 85 85 120 121 122 7 9 9 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 82 82 81 12 12 12 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 19 19 19 81 81 82 0 0 0
+0 0 0 2 2 2 8 8 8 55 63 63 108 110 110 52 58 58
+0 0 0 0 0 0 0 0 0 0 0 0 42 42 43 129 130 130
+140 142 143 114 115 115 110 114 114 129 130 130 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 75 75 76 24 24 24 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 19 19 19 74 74 74 0 0 0
+4 6 6 167 168 167 196 196 197 196 196 197 61 65 66 78 85 85
+0 0 0 0 0 0 0 0 0 118 118 118 202 202 203 219 219 219
+219 219 219 214 214 215 187 187 188 78 85 85 29 33 34 0 0 0
+0 0 0 0 0 0 0 0 0 60 60 60 39 39 39 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 19 19 19 72 71 71 0 0 0
+185 185 184 244 245 245 250 251 252 251 251 252 247 248 249 36 36 36
+0 0 0 0 0 0 13 13 13 243 243 241 252 252 252 253 253 253
+253 253 253 252 252 252 247 247 246 193 193 194 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 42 42 43 50 51 51 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 19 19 19 78 81 81 0 0 0
+247 247 246 193 193 194 95 97 97 193 193 194 255 255 255 237 237 238
+0 0 0 0 0 0 202 202 203 255 255 255 247 247 246 108 107 107
+82 85 86 167 168 167 255 255 255 248 248 249 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 34 34 35 56 56 56 2 2 2
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 19 19 19 78 81 81 0 0 0
+250 250 251 50 51 51 153 154 155 150 151 151 244 245 245 244 245 245
+44 50 50 84 89 89 153 154 155 255 255 255 140 142 143 0 0 0
+149 149 150 156 155 156 237 237 238 254 254 254 67 70 70 0 0 0
+0 0 0 0 0 0 0 0 0 39 39 39 47 47 47 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 19 19 19 81 81 82 0 0 0
+248 248 249 34 34 35 72 71 71 165 165 165 202 202 203 244 245 245
+10 16 16 82 85 86 89 90 91 255 255 255 95 97 97 0 0 0
+0 0 0 53 54 54 177 177 174 255 255 255 127 127 126 0 0 0
+0 0 0 0 0 0 0 0 0 39 39 39 36 36 36 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 14 14 14 78 81 81 0 0 0
+243 243 243 89 90 91 0 0 0 36 40 40 201 147 55 241 205 27
+241 205 27 241 205 27 241 205 27 238 192 33 108 110 110 0 0 0
+0 0 0 0 0 0 191 190 190 254 254 254 34 34 35 0 0 0
+0 0 0 0 0 0 0 0 0 42 42 43 42 42 43 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 10 10 10 75 75 76 0 0 0
+202 202 203 218 217 217 21 19 17 230 165 41 199 129 48 213 157 40
+244 212 23 243 206 27 180 121 62 243 206 27 244 209 25 226 179 40
+15 10 7 103 103 103 254 254 254 251 251 252 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 17 18 18 58 58 58 2 2 2
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 9 9 9 84 84 84 0 0 0
+0 0 0 226 226 219 213 157 40 244 209 25 245 211 23 245 211 23
+245 214 38 245 214 38 245 211 23 245 211 23 245 211 23 244 212 23
+244 212 23 241 205 27 226 179 40 196 196 197 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 74 74 74 4 6 6
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 7 7 7 84 84 84 0 0 0
+54 42 32 213 157 40 243 206 27 245 211 23 245 211 23 245 211 23
+245 215 41 245 214 35 245 211 23 245 211 23 245 214 35 245 215 41
+245 214 35 245 211 23 245 211 23 238 204 29 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 81 81 82 12 12 12
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 4 6 6 74 74 74 0 0 0
+201 147 55 241 205 27 245 211 23 245 211 23 245 211 23 245 213 29
+245 214 38 245 211 23 245 211 23 245 214 35 245 215 41 245 215 41
+245 213 29 142 83 36 142 83 36 244 209 25 1 1 1 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 74 74 74 25 25 26
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 4 4 4 72 71 71 6 6 6
+213 157 40 244 209 25 245 211 23 245 211 23 245 211 23 245 213 29
+244 212 23 245 211 23 245 214 35 245 215 41 245 215 41 245 213 29
+142 83 36 142 83 36 238 192 33 241 205 27 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 44 44 44 49 50 50
+2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 3 3 3 65 64 64 17 18 18
+199 129 48 199 129 48 245 211 23 245 211 23 245 211 23 245 211 23
+245 211 23 244 212 23 245 214 38 245 214 38 142 83 36 142 83 36
+142 83 36 245 211 23 244 210 23 230 165 41 0 0 0 0 0 0
+78 81 81 114 115 115 73 79 79 0 0 0 3 3 3 81 81 82
+9 9 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 1 1 1 49 50 50 29 29 30
+90 87 86 199 129 48 173 101 51 173 101 51 245 211 23 245 211 23
+245 211 23 230 165 41 142 83 36 142 83 36 142 83 36 245 211 23
+244 210 23 241 205 27 230 165 41 175 173 165 3 3 3 0 0 0
+44 46 46 118 118 118 118 118 118 108 110 110 0 0 0 75 75 76
+28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 1 1 1 52 53 53 26 26 27
+118 118 118 175 173 165 199 129 48 173 101 51 173 101 51 173 101 51
+173 101 51 142 83 36 173 101 51 245 211 23 244 209 25 238 204 29
+213 157 40 214 196 166 227 227 227 214 214 215 120 121 122 0 0 0
+0 0 0 108 110 110 118 118 118 118 118 118 0 0 0 23 23 23
+66 66 66 4 6 6 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 7 7 7 75 75 76 4 4 4
+127 127 126 205 205 205 181 181 181 199 129 48 226 179 40 244 209 25
+244 209 25 244 209 25 243 206 27 238 192 33 213 157 40 187 166 103
+234 234 234 248 248 249 251 252 252 248 248 249 214 214 215 0 0 0
+0 0 0 0 0 0 103 103 103 100 103 103 0 0 0 0 0 0
+78 81 81 24 24 24 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 26 27 27 82 82 81 0 0 0
+146 146 147 234 234 234 222 221 221 178 178 179 180 121 62 213 157 40
+213 157 40 213 157 40 201 147 55 180 121 62 219 219 219 243 243 241
+253 253 253 255 255 255 255 255 255 255 255 255 250 250 251 120 121 122
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+20 20 20 72 71 71 8 8 8 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 10 10 10 75 75 76 22 22 22 0 0 0
+205 205 205 253 253 253 247 248 249 212 211 212 178 178 179 161 161 162
+165 165 165 181 181 181 205 205 205 227 227 227 244 245 245 254 254 254
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 239 240
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 67 70 70 39 39 39 2 2 2 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 4 4 4 50 51 51 60 60 60 0 0 0 16 16 16
+249 250 251 255 255 255 255 255 255 240 240 240 209 210 210 193 193 194
+200 200 197 212 211 212 231 231 231 246 247 248 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 253 253
+153 154 155 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 3 3 3 84 84 84 20 20 20 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+2 2 2 33 33 34 81 81 82 0 0 0 0 0 0 231 231 231
+255 255 255 255 255 255 255 255 255 253 253 253 234 234 234 222 221 221
+227 227 227 237 237 238 250 250 251 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+240 240 240 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 26 27 27 72 71 71 8 8 8 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+21 21 22 84 84 84 7 7 7 0 0 0 150 151 151 252 252 252
+255 255 255 255 255 255 255 255 255 255 255 255 252 252 252 244 245 245
+246 247 248 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+251 251 252 9 9 9 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 65 64 64 47 47 47 3 3 3
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 12 12
+75 75 76 26 26 27 0 0 0 1 1 1 239 239 240 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 202 202 203 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 84 84 84 28 28 29
+1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 55 55 55
+60 60 60 0 0 0 0 0 0 95 97 97 248 248 249 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 244 245 245 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 82 82 81
+15 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 1 1 1 29 29 30 84 84 84
+0 0 0 0 0 0 0 0 0 156 155 156 247 247 246 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 247 247 246 240 240 240 232 232 233 232 232 233
+243 243 243 253 253 253 53 54 54 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 44 44
+60 60 60 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 10 10 10 81 81 82 14 14 14
+0 0 0 0 0 0 6 6 6 150 151 151 214 214 215 250 251 252
+255 255 255 255 255 255 255 255 255 246 247 248 218 217 217 214 214 215
+218 217 217 244 245 245 255 255 255 255 255 255 255 255 255 250 248 249
+232 232 233 214 214 215 196 196 197 182 183 184 181 181 181 181 181 181
+187 187 188 240 240 240 232 232 233 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+78 81 81 34 34 35 1 1 1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 1 1 39 39 39 74 74 74 0 0 0
+0 0 0 0 0 0 60 60 60 161 161 162 200 200 197 229 229 230
+251 251 252 255 255 255 255 255 255 255 255 255 243 243 241 214 214 215
+248 248 249 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254
+239 239 240 214 214 215 193 193 194 182 183 184 178 178 179 176 177 177
+176 177 177 182 183 184 248 248 249 14 14 14 0 0 0 61 65 66
+10 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+10 10 10 84 84 84 13 13 13 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 10 11 11 82 82 81 7 7 7 0 0 0
+0 0 0 0 0 0 165 165 165 229 229 230 249 250 251 254 254 254
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 253 253 253 240 240 240 227 227 227 205 205 205
+181 181 181 176 177 177 191 190 190 227 227 227 0 0 0 44 50 50
+84 89 89 61 65 66 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 58 58 58 49 50 50 3 3 3 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 36 36 36 66 66 66 0 0 0 29 33 34
+0 3 3 26 27 27 234 234 234 254 254 254 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+254 254 254 253 253 254 252 253 253 253 253 254 253 254 254 253 254 254
+254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 251 251 252
+227 227 227 187 187 188 176 177 177 222 221 221 13 13 13 0 0 0
+12 15 14 73 79 79 36 40 40 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 90 87 86 17 18 18 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 7 7 7 78 81 81 12 12 12 23 31 30 52 58 58
+0 0 0 209 210 210 253 253 253 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254
+251 251 252 150 151 151 103 103 103 129 130 130 196 196 197 250 250 251
+252 252 253 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 240 240 240 193 193 194 196 196 197 229 229 230 0 0 0
+0 0 0 4 10 10 30 40 40 0 3 3 0 0 0 0 0 0
+0 0 0 0 0 0 47 47 47 53 54 54 3 3 3 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 23 23 23 81 81 82 0 0 0 52 58 58 36 40 40
+42 42 43 250 250 251 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254
+227 227 227 7 7 7 7 7 7 7 7 7 7 7 7 44 44 45
+156 155 156 249 250 251 253 253 253 254 254 254 255 255 255 255 255 255
+255 255 255 255 255 255 247 247 246 222 221 221 239 239 240 0 0 0
+30 40 40 44 50 50 23 31 30 29 33 34 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 90 87 86 16 16 16 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+2 2 2 50 51 51 42 42 43 29 33 34 52 58 58 0 0 0
+232 232 233 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254
+250 251 252 44 44 44 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 56 56 56 209 210 210 252 252 253 254 254 254 255 255 255
+255 255 255 255 255 255 255 255 255 254 253 253 249 250 251 146 146 147
+36 40 40 44 50 50 36 40 40 67 70 70 61 65 66 0 0 0
+0 0 0 0 0 0 0 0 0 55 55 55 44 44 45 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+10 10 10 81 81 82 1 1 1 52 58 58 44 50 50 52 53 53
+251 251 252 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 254
+253 253 253 187 187 188 8 8 8 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 19 19 19 178 178 179 252 252 253 254 254 254
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 237 237 238
+10 16 16 30 40 40 0 3 3 23 31 30 84 89 89 0 0 0
+0 0 0 0 0 0 0 0 0 3 3 3 81 81 82 9 9 9
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+29 29 30 72 71 71 10 16 16 52 58 58 0 0 0 222 221 221
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+254 254 254 251 251 252 95 97 97 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 10 10 10 161 161 162 251 252 252
+254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 248 248 249
+0 0 0 0 0 0 0 0 0 0 0 0 84 89 89 0 3 3
+0 0 0 0 0 0 0 0 0 0 0 0 74 74 74 26 27 27
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4
+65 64 64 20 20 20 20 25 25 30 40 40 0 0 0 247 247 246
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 253 253 254 222 221 221 9 9 9 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 149 149 150
+252 252 253 254 254 254 255 255 255 255 255 255 255 255 255 252 252 252
+0 0 0 0 0 0 0 0 0 0 0 0 73 79 79 12 15 14
+0 0 0 0 0 0 0 0 0 0 0 0 36 36 36 58 58 58
+3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 20 20
+74 74 74 0 0 0 4 10 10 4 10 10 36 36 36 252 252 252
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 227 227 227 253 253 253 255 255 255
+255 255 255 254 254 254 250 251 252 65 64 64 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8
+146 146 147 251 252 252 254 254 254 255 255 255 255 255 255 253 254 254
+0 0 0 0 0 0 0 0 0 0 0 0 52 58 58 10 16 16
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 82 81
+9 9 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 4 6 6 65 64 64
+25 25 25 0 3 3 30 40 40 0 0 0 187 187 188 254 254 254
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 193 193 194 253 252 252 255 255 255
+255 255 255 255 255 255 252 253 253 129 130 130 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+8 8 8 149 149 150 252 252 253 254 254 254 255 255 255 254 254 254
+52 53 53 0 0 0 0 0 0 0 0 0 20 25 25 2 5 4
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 81 82
+20 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 26 26 27 81 81 82
+0 0 0 18 21 21 73 79 79 0 0 0 237 237 238 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 182 183 184 255 255 255 255 255 255
+255 255 255 255 255 255 253 253 253 176 177 177 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 8 8 8 153 154 155 251 252 252 254 254 254 255 255 255
+150 151 151 0 0 0 0 0 0 0 0 0 20 25 25 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65 64 64
+33 33 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 6 6 6 67 70 70 20 20 20
+0 0 0 23 31 30 82 85 86 0 0 0 247 247 246 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 182 183 184 255 255 255 255 255 255
+255 255 255 255 255 255 253 254 254 214 214 215 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 8 8 8 156 155 156 252 252 253 254 254 254
+167 168 167 0 0 0 0 0 0 0 0 0 67 70 70 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 47 47
+44 44 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 21 21 22 75 75 76 0 0 0
+0 0 0 29 33 34 84 89 89 0 0 0 248 248 249 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 248 248 249 181 181 181 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 240 240 240 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 8 8 8 161 161 162 251 252 252
+185 185 184 4 4 4 0 0 0 10 11 11 100 103 103 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 36 36
+55 55 55 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 33 33 34 50 51 51 0 0 0
+0 0 0 9 11 11 82 85 86 10 16 16 248 248 249 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 245 244 245 179 180 181 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 251 252 252 20 20 20 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 10 10 10 161 161 162
+205 205 205 17 18 18 0 0 0 95 97 97 78 81 81 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 36 36
+53 54 54 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 31 31 31 58 58 58 0 0 0
+0 0 0 0 0 0 67 70 70 78 81 81 248 248 249 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 234 234 234 179 180 181 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 251 252 252 23 23 23 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+10 11 11 84 84 84 161 161 162 209 210 210 229 229 230 237 237 238
+202 202 203 26 26 27 9 11 11 44 50 50 0 0 0 4 6 6
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 53 53
+39 39 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 23 23 23 78 81 81 213 157 40
+243 206 27 243 206 27 54 42 32 73 79 79 222 221 221 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 238 238 236 178 178 179 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 251 252 253 36 36 36 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 84 84 84
+222 221 221 251 252 252 252 253 253 253 253 253 253 254 254 252 252 253
+146 146 147 140 142 143 156 155 156 110 114 114 26 27 27 82 85 86
+84 89 89 95 97 97 36 40 40 0 0 0 0 0 0 74 74 74
+23 23 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 14 14 14
+24 24 24 26 26 27 26 26 27 26 26 27 25 25 26 21 21 22
+7 7 7 0 0 0 1 1 1 34 34 35 238 192 33 244 210 23
+244 212 23 244 212 23 244 210 23 88 79 47 200 200 197 254 254 254
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 244 245 245 179 180 181 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 252 252 253 36 36 36 7 7 7
+7 7 7 7 7 7 7 7 7 8 8 8 149 149 150 251 251 252
+252 252 253 253 253 253 253 253 253 250 248 249 239 223 156 239 223 156
+120 121 122 182 183 184 176 177 177 120 121 122 33 33 34 3 3 3
+0 0 0 67 70 70 146 146 147 20 25 25 1 1 1 82 82 81
+9 9 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 19 19 19 89 90 91
+146 146 147 150 151 151 150 151 151 150 151 151 150 151 151 129 130 130
+58 58 58 6 6 6 14 14 14 201 147 55 245 211 23 245 213 29
+245 214 35 245 215 41 245 213 29 244 210 23 142 83 36 232 232 233
+254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 185 185 184 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 251 252 252 50 51 51 7 7 7
+7 7 7 7 7 7 7 7 7 146 146 147 251 252 252 252 253 253
+251 252 253 239 239 240 171 168 154 129 130 130 137 136 134 175 173 165
+221 218 200 65 64 64 22 22 22 186 186 187 114 115 115 26 26 27
+2 2 2 0 0 0 61 65 66 31 33 27 238 192 33 108 96 91
+9 9 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 2 2 2 52 53 53 178 178 179
+21 21 22 7 7 7 7 7 7 7 7 7 7 7 7 118 118 118
+137 136 134 36 36 36 65 64 64 243 206 27 244 212 23 245 215 41
+245 215 41 245 215 41 245 215 41 244 209 25 244 209 25 1 1 1
+219 219 219 253 253 253 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 214 214 215 255 255 255 255 255 255
+255 255 255 255 255 255 254 254 254 252 252 253 50 51 51 7 7 7
+7 7 7 7 7 7 84 84 84 250 251 252 252 253 253 251 251 252
+167 168 167 22 22 22 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 34 34 35 187 187 188 103 103 103
+29 29 30 3 3 3 7 9 9 238 204 29 245 215 41 245 214 35
+28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 7 7 7 90 87 86 178 178 179
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 16 16 16
+193 193 194 133 133 133 187 166 103 245 218 76 245 218 76 245 216 51
+245 216 51 245 218 76 246 224 96 245 218 76 245 218 76 245 218 76
+25 25 25 186 186 187 252 252 252 254 254 254 254 254 254 253 254 254
+254 254 254 254 254 254 254 254 254 246 247 248 254 254 254 253 254 254
+254 254 254 254 254 254 253 254 254 251 252 252 36 36 36 7 7 7
+7 7 7 20 20 20 229 229 230 253 253 253 252 253 253 178 178 179
+10 10 10 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 42 42 43 196 196 197
+118 118 118 33 33 34 238 204 29 245 215 41 245 215 41 245 215 41
+49 50 50 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 17 18 18 120 121 122 137 136 134
+7 7 7 7 7 7 34 34 35 20 20 20 7 7 7 7 7 7
+202 202 203 209 206 202 193 187 162 193 187 162 248 234 156 245 218 76
+245 218 76 248 234 156 193 187 162 193 187 162 193 187 162 214 196 166
+240 219 129 95 97 97 196 196 197 186 186 187 187 187 188 196 196 197
+252 252 253 251 252 253 212 211 212 187 187 188 196 196 197 251 252 252
+218 217 217 187 187 188 191 190 190 250 251 252 24 24 24 7 7 7
+7 7 7 110 114 114 252 252 253 253 254 254 250 251 252 89 90 91
+89 90 91 129 130 130 127 127 126 44 44 44 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 49 50 50
+202 202 203 214 196 166 245 216 51 245 214 38 245 214 35 245 214 38
+58 58 58 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 31 31 31 156 155 156 82 82 81
+7 7 7 10 10 10 237 237 238 66 66 66 7 7 7 25 25 25
+247 248 249 81 81 82 7 7 7 31 31 31 247 237 174 245 218 76
+246 226 108 200 200 197 7 7 7 7 7 7 7 7 7 137 136 134
+247 237 174 193 193 194 72 71 71 7 7 7 7 7 7 8 8 8
+196 196 197 250 251 252 67 70 70 7 7 7 84 84 84 244 245 245
+47 47 47 7 7 7 118 118 118 249 250 251 12 12 12 7 7 7
+9 9 9 218 217 217 253 253 253 254 254 254 252 253 253 251 251 252
+249 250 251 237 237 238 95 97 97 9 9 9 15 15 15 95 97 97
+47 47 47 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+66 66 66 240 230 197 246 226 108 245 214 38 245 211 23 244 212 23
+65 64 64 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 2 2 2 52 53 53 185 185 184 25 25 25
+7 7 7 60 60 60 240 240 240 14 14 14 7 7 7 84 84 84
+247 248 249 23 23 23 7 7 7 94 91 88 248 234 156 245 218 76
+248 234 156 127 127 126 7 7 7 7 7 7 7 7 7 167 168 167
+251 248 240 65 64 64 7 7 7 7 7 7 7 7 7 7 7 7
+84 84 84 243 243 243 15 15 15 7 7 7 140 142 143 146 146 147
+7 7 7 33 33 34 237 237 238 243 243 243 21 21 22 120 121 122
+218 217 217 252 252 253 254 254 254 253 253 254 252 253 253 251 252 252
+247 248 249 72 71 71 7 7 7 58 58 58 222 221 221 248 248 249
+75 75 76 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 82 82 81 246 239 193 246 226 108 245 216 51 245 214 38
+238 192 33 21 21 22 1 1 1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 8 8 8 90 87 86 182 183 184 7 7 7
+7 7 7 120 121 122 187 187 188 7 7 7 7 7 7 146 146 147
+205 205 205 7 7 7 7 7 7 153 153 148 240 219 129 246 224 96
+246 239 193 39 39 39 60 60 60 108 110 110 7 7 7 202 202 203
+227 227 227 7 7 7 7 7 7 205 205 205 89 90 91 7 7 7
+120 121 122 193 193 194 7 7 7 7 7 7 186 186 187 25 25 25
+7 7 7 167 168 167 251 251 252 243 243 243 214 214 215 250 251 252
+251 252 253 254 254 254 253 253 253 219 219 219 140 140 139 140 140 139
+118 118 118 7 7 7 52 53 53 237 237 238 247 247 246 176 177 177
+8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 95 97 97 246 239 193 246 226 108 245 216 51
+245 214 38 201 147 55 31 31 31 103 103 103 103 103 103 72 71 71
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 17 18 18 127 127 126 140 140 139 7 7 7
+7 7 7 17 18 18 17 18 18 7 7 7 95 97 97 244 245 245
+146 146 147 7 7 7 7 7 7 200 200 197 246 226 108 240 219 129
+194 194 184 7 7 7 140 140 139 89 90 91 7 7 7 232 232 233
+165 165 165 7 7 7 31 31 31 249 250 251 39 39 39 7 7 7
+176 177 177 133 133 133 7 7 7 22 22 22 108 110 110 7 7 7
+72 71 71 251 252 252 252 253 253 250 251 252 247 248 249 205 205 205
+251 252 253 254 254 254 252 252 253 84 84 84 7 7 7 7 7 7
+7 7 7 7 7 7 140 142 143 247 248 249 140 140 139 14 14 14
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 16 16 16
+14 14 14 7 7 7 7 7 7 114 115 115 246 239 193 246 224 96
+245 216 51 245 216 51 243 235 220 176 177 177 185 185 184 229 229 230
+47 47 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 31 31 31 156 155 156 90 87 86 7 7 7
+7 7 7 7 7 7 7 7 7 31 31 31 243 243 241 247 247 246
+84 84 84 7 7 7 26 27 27 246 239 193 246 226 108 248 234 156
+108 110 110 7 7 7 212 211 212 44 44 44 22 22 22 249 250 251
+108 107 107 7 7 7 89 90 91 238 238 236 114 115 115 118 118 118
+231 231 231 75 75 76 7 7 7 34 34 35 10 11 11 12 12 12
+214 214 215 253 253 253 253 253 253 200 200 197 31 31 31 103 103 103
+252 252 253 252 253 253 218 217 217 9 9 9 7 7 7 7 7 7
+7 7 7 7 7 7 25 25 25 39 39 39 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 103 103 103 234 234 234
+181 181 181 7 7 7 7 7 7 7 7 7 133 133 133 247 237 174
+246 224 96 246 226 108 185 185 184 177 177 174 153 154 155 181 181 181
+140 140 139 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 1 1 1 49 50 50 186 186 187 28 28 28 7 7 7
+12 12 12 22 22 22 7 7 7 7 7 7 108 107 107 247 247 246
+25 25 25 7 7 7 90 87 86 247 237 174 246 226 108 246 239 193
+28 28 28 44 44 44 237 237 238 9 9 9 53 54 54 249 250 251
+49 50 50 7 7 7 153 153 148 249 241 199 214 196 166 185 185 184
+229 229 230 19 19 19 7 7 7 7 7 7 7 7 7 103 103 103
+251 252 253 254 254 254 253 253 253 150 151 151 7 7 7 187 187 188
+252 252 253 251 251 252 103 103 103 7 7 7 7 7 7 7 7 7
+7 7 7 23 23 23 17 18 18 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 12 12 12 153 153 148 246 239 193 249 241 199
+161 161 162 9 9 9 84 84 84 108 110 110 25 25 25 153 153 148
+247 237 174 246 224 96 218 217 217 165 165 165 182 183 184 193 193 194
+114 115 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 4 4 4 74 74 74 181 181 181 7 7 7 7 7 7
+110 114 114 200 200 197 7 7 7 7 7 7 60 60 60 209 210 210
+7 7 7 7 7 7 146 146 147 248 234 156 248 234 156 177 177 174
+7 7 7 118 118 118 193 193 194 7 7 7 84 84 84 232 232 233
+8 8 8 7 7 7 209 210 210 221 218 200 193 187 162 219 219 219
+200 200 197 7 7 7 7 7 7 7 7 7 7 7 7 95 97 97
+251 252 252 254 254 254 252 253 253 118 118 118 29 29 30 247 248 249
+252 252 253 227 227 227 16 16 16 7 7 7 7 7 7 7 7 7
+100 103 103 218 217 217 219 218 214 7 7 7 7 7 7 7 7 7
+7 7 7 21 21 22 185 185 184 246 239 193 248 234 156 240 230 197
+60 60 60 194 194 184 246 239 193 249 241 199 137 136 134 10 10 10
+171 168 154 248 234 156 248 234 156 226 226 219 209 210 210 249 241 199
+28 28 28 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 13 13 13 108 110 110 146 146 147 7 7 7 7 7 7
+167 168 167 140 140 139 7 7 7 7 7 7 120 121 122 146 146 147
+7 7 7 7 7 7 194 194 184 240 219 129 247 237 174 95 97 97
+7 7 7 95 97 97 90 87 86 7 7 7 118 118 118 176 177 177
+7 7 7 28 28 28 248 248 249 44 44 45 7 7 7 167 168 167
+140 140 139 7 7 7 36 36 36 74 74 74 7 7 7 65 64 64
+251 252 253 254 254 254 251 252 252 81 81 82 108 110 110 251 252 252
+251 251 252 127 127 126 7 7 7 7 7 7 8 8 8 140 140 139
+181 181 181 140 140 139 221 218 200 7 7 7 7 7 7 7 7 7
+34 34 35 209 210 210 231 231 231 246 239 193 247 237 174 194 194 184
+227 227 227 249 241 199 240 219 129 248 234 156 153 153 148 7 7 7
+13 13 13 185 185 184 248 234 156 245 218 76 245 216 51 245 214 38
+31 31 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 31 31 31 153 154 155 89 90 91 7 7 7 8 8 8
+232 232 233 82 82 81 7 7 7 7 7 7 179 180 181 89 90 91
+7 7 7 24 24 24 243 235 220 248 234 156 240 230 197 20 20 20
+7 7 7 7 7 7 7 7 7 7 7 7 149 149 150 118 118 118
+7 7 7 90 87 86 229 229 230 7 7 7 7 7 7 229 229 230
+82 82 81 7 7 7 95 97 97 100 103 103 7 7 7 34 34 35
+251 252 252 253 253 254 251 251 252 47 47 47 193 193 194 251 252 252
+239 239 240 23 23 23 7 7 7 13 13 13 165 165 165 234 234 234
+149 149 150 146 114 101 200 200 197 7 7 7 7 7 7 52 53 53
+227 227 227 167 168 167 16 16 16 214 196 166 248 234 156 243 235 220
+219 219 219 156 155 156 247 237 174 246 239 193 75 75 76 7 7 7
+60 60 60 227 227 227 243 235 220 240 219 129 245 218 76 245 213 29
+16 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+1 1 1 49 50 50 185 185 184 33 33 34 7 7 7 10 11 11
+56 56 56 16 16 16 7 7 7 10 10 10 237 237 238 26 27 27
+7 7 7 55 55 55 185 185 184 221 218 200 167 168 167 7 7 7
+20 20 20 39 39 39 10 11 11 7 7 7 181 181 181 58 58 58
+7 7 7 103 103 103 133 133 133 7 7 7 44 44 44 247 248 249
+24 24 24 7 7 7 156 155 156 129 130 130 7 7 7 9 9 9
+244 245 245 252 253 253 237 237 238 34 34 35 248 248 249 251 251 252
+161 161 162 7 7 7 24 24 24 187 187 188 212 211 212 67 70 70
+187 187 188 173 170 143 209 206 202 10 10 10 95 97 97 237 237 238
+129 130 130 8 8 8 89 90 91 246 239 193 247 237 174 177 177 174
+17 18 18 137 136 134 249 241 199 219 218 214 10 10 10 95 97 97
+243 243 243 150 151 151 31 31 31 221 218 200 240 219 129 53 54 54
+3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+4 4 4 72 71 71 182 183 184 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 12 12 12 161 161 162 209 210 210 7 7 7
+7 7 7 7 7 7 7 7 7 187 187 188 82 82 81 7 7 7
+146 146 147 247 248 249 17 18 18 7 7 7 212 211 212 47 47 47
+7 7 7 7 7 7 7 7 7 8 8 8 146 146 147 205 205 205
+7 7 7 7 7 7 214 214 215 156 155 156 7 7 7 7 7 7
+218 217 217 251 252 252 186 186 187 110 114 114 249 250 251 248 248 249
+75 75 76 34 34 35 205 205 205 129 130 130 16 16 16 7 7 7
+156 155 156 214 196 166 240 230 197 243 243 241 227 227 227 74 74 74
+7 7 7 29 29 30 226 226 219 249 241 199 175 173 165 14 14 14
+9 9 9 221 218 200 246 239 193 153 153 148 146 146 147 246 247 248
+110 114 114 7 7 7 7 7 7 42 42 43 193 193 194 95 97 97
+19 19 19 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+6 6 6 84 84 84 140 142 143 7 7 7 7 7 7 7 7 7
+7 7 7 20 20 20 177 177 174 249 241 199 149 149 150 7 7 7
+7 7 7 7 7 7 10 11 11 226 226 219 13 13 13 8 8 8
+219 218 214 219 218 214 7 7 7 8 8 8 238 238 236 200 200 197
+13 13 13 7 7 7 13 13 13 161 161 162 243 235 220 146 146 147
+7 7 7 29 29 30 232 232 233 176 177 177 7 7 7 7 7 7
+182 183 184 237 237 238 129 130 130 167 168 167 176 177 177 202 202 203
+10 11 11 95 97 97 44 44 45 7 7 7 7 7 7 7 7 7
+75 75 76 226 226 219 243 235 220 156 155 156 24 24 24 7 7 7
+7 7 7 176 177 177 247 247 246 200 200 197 17 18 18 7 7 7
+49 50 50 246 239 193 248 234 156 251 248 240 239 239 240 84 84 84
+7 7 7 7 7 7 7 7 7 7 7 7 60 60 60 187 187 188
+84 84 84 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+4 4 4 53 54 54 137 136 134 156 155 156 161 161 162 161 161 162
+167 168 167 239 223 156 240 219 129 246 226 108 239 223 156 239 223 156
+239 223 156 239 223 156 214 196 166 239 223 156 193 187 162 193 187 162
+248 234 156 239 223 156 193 187 162 193 187 162 248 234 156 248 234 156
+214 196 166 193 187 162 214 196 166 248 234 156 240 219 129 214 196 166
+193 187 162 193 187 162 171 168 154 146 146 147 137 136 134 137 136 134
+161 161 162 209 210 210 65 64 64 202 202 203 179 180 181 140 140 139
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 60 60 60 39 39 39 7 7 7 7 7 7 7 7 7
+66 66 66 249 250 251 202 202 203 16 16 16 7 7 7 7 7 7
+23 23 23 243 235 220 246 239 193 226 226 219 52 53 53 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 75 75 76
+176 177 177 66 66 66 9 9 9 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 10 10 10 28 28 29 34 34 35 36 36 36 36 36 36
+44 44 45 146 114 101 241 207 50 241 207 50 241 207 50 241 211 63
+241 211 63 241 211 63 241 211 63 241 211 63 241 211 63 245 216 51
+245 216 51 245 216 51 241 211 63 241 211 63 245 216 51 241 211 63
+245 218 76 245 218 76 245 216 51 245 215 41 245 214 38 241 207 50
+241 211 63 201 147 55 88 79 47 29 29 30 34 34 35 42 42 43
+103 103 103 191 190 190 75 75 76 196 196 197 200 200 197 65 64 64
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+90 87 86 146 146 147 19 19 19 7 7 7 7 7 7 7 7 7
+7 7 7 90 87 86 140 140 139 31 31 31 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+103 103 103 161 161 162 53 54 54 7 7 7 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 12 12 12 50 51 51 146 114 101 180 121 62 199 129 48
+201 147 55 213 157 40 213 157 40 230 165 41 226 179 40 226 179 40
+238 192 33 241 205 27 244 209 25 244 210 23 244 212 23 245 211 23
+245 211 23 245 211 23 245 211 23 244 209 25 238 204 29 226 179 40
+213 157 40 199 129 48 54 42 32 0 0 0 4 6 6 44 44 45
+150 151 151 129 130 130 137 136 134 205 205 205 202 202 203 8 8 8
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 129 130 130 146 146 147 47 47 47 4 4 4 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 2 2 2 12 12 12 28 28 29 49 50 50
+74 74 74 108 96 91 180 121 62 180 121 62 199 129 48 201 147 55
+213 157 40 230 165 41 226 179 40 238 192 33 241 205 27 241 205 27
+243 206 27 243 206 27 241 205 27 238 204 29 226 179 40 213 157 40
+199 129 48 199 129 48 21 19 17 65 64 64 103 103 103 167 168 167
+202 202 203 24 24 24 193 193 194 229 229 230 140 140 139 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 8 8 8 156 155 156 133 133 133 36 36 36 3 3 3
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+4 4 4 10 11 11 21 21 22 39 39 39 60 60 60 108 96 91
+180 121 62 199 129 48 199 129 48 213 157 40 230 165 41 226 179 40
+226 179 40 226 179 40 226 179 40 226 179 40 213 157 40 199 129 48
+180 121 62 99 91 79 72 71 71 56 56 56 129 130 130 167 168 167
+21 21 22 17 18 18 231 231 231 229 229 230 52 53 53 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 13 13 13 176 177 177 120 121 122 33 33 34
+2 2 2 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 8 8 8
+21 21 22 47 47 47 99 91 79 180 121 62 199 129 48 199 129 48
+201 147 55 213 157 40 213 157 40 201 147 55 199 129 48 180 121 62
+99 91 79 26 26 27 9 9 9 60 60 60 186 186 187 31 31 31
+7 7 7 60 60 60 243 243 243 209 210 210 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
+7 7 7 7 7 7 7 7 7 26 27 27 193 193 194 108 110 110
+22 22 22 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 8 8 8 24 24 24 58 58 58 108 96 91
+180 121 62 180 121 62 180 121 62 180 121 62 180 121 62 72 71 71
+15 15 15 0 0 0 4 6 6 75 75 76 156 155 156 24 24 24
+24 24 24 108 107 107 232 232 233 137 136 134 24 24 24 24 24 24
+24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
+24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
+24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
+24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
+24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24
+24 24 24 24 24 24 24 24 24 24 24 24 58 58 58 176 177 177
+60 60 60 3 3 3
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 12 12 12
+26 27 27 44 44 44 55 55 55 50 51 51 29 29 30 8 8 8
+0 0 0 0 0 0 3 3 3 47 47 47 127 127 126 150 151 151
+150 151 151 140 142 143 129 130 130 140 142 143 150 151 151 150 151 151
+150 151 151 150 151 151 150 151 151 150 151 151 150 151 151 150 151 151
+150 151 151 150 151 151 153 154 155 161 161 162 165 165 165 167 168 167
+177 177 174 167 168 167 161 161 162 156 155 156 150 151 151 150 151 151
+150 151 151 150 151 151 150 151 151 150 151 151 150 151 151 150 151 151
+150 151 151 150 151 151 150 151 151 150 151 151 150 151 151 150 151 151
+150 151 151 150 151 151 150 151 151 150 151 151 149 149 150 127 127 126
+44 44 45 2 2 2
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 2 2 2 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 7 7 7 21 21 22 25 25 26
+25 25 26 24 24 24 20 20 20 23 23 24 25 25 26 26 26 27
+26 26 27 26 26 27 26 26 27 26 26 27 26 26 27 26 26 27
+26 26 27 26 26 27 26 26 27 26 26 27 26 26 27 26 27 27
+28 28 29 26 27 27 26 26 27 26 26 27 26 26 27 26 26 27
+26 26 27 26 26 27 26 26 27 26 26 27 26 26 27 26 26 27
+26 26 27 26 26 27 26 26 27 26 26 27 26 26 27 26 26 27
+26 26 27 26 26 27 26 26 27 26 26 27 25 25 26 21 21 22
+7 7 7 0 0 0
diff --git a/drivers/video/logo/logo_blackfin_vga16.ppm b/drivers/video/logo/logo_blackfin_vga16.ppm
new file mode 100644
index 000000000000..1352b02a9d93
--- /dev/null
+++ b/drivers/video/logo/logo_blackfin_vga16.ppm
@@ -0,0 +1,1127 @@
+P3
+# This was generated by the GIMP & Netpbm tools
+# gimp linux_bf.svg (create 80x80 save as linux_bf.ppm)
+# ppmquant -mapfile clut_vga16.ppm linux_bf.ppm | pnmnoraw > logo_blackfin_vga16.ppm
+#
+80 80
+255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 85 85 85 85 85 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 85 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 85 85 85 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 170 170 170 170 170 170 85 85 85 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 85 85 85 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 170 170
+170 170 170 85 85 85 85 85 85 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 170 170 170 170 170 170 170 170 170 85 85 85 85 85 85
+0 0 0 0 0 0 0 0 0 85 85 85 170 170 170 255 255 255
+255 255 255 255 255 255 170 170 170 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+170 170 170 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0
+0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+255 255 255 170 170 170 85 85 85 170 170 170 255 255 255 255 255 255
+0 0 0 0 0 0 170 170 170 255 255 255 255 255 255 85 85 85
+85 85 85 170 170 170 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+255 255 255 85 85 85 170 170 170 170 170 170 255 255 255 255 255 255
+85 85 85 85 85 85 170 170 170 255 255 255 170 170 170 0 0 0
+170 170 170 170 170 170 255 255 255 255 255 255 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+255 255 255 0 0 0 85 85 85 170 170 170 170 170 170 255 255 255
+0 0 0 85 85 85 85 85 85 255 255 255 85 85 85 0 0 0
+0 0 0 85 85 85 170 170 170 255 255 255 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+255 255 255 85 85 85 0 0 0 0 0 0 255 85 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 85 85 85 0 0 0
+0 0 0 0 0 0 170 170 170 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+170 170 170 255 255 255 0 0 0 255 85 85 170 85 0 170 85 0
+255 255 85 255 255 85 170 85 0 255 255 85 255 255 85 255 255 85
+0 0 0 85 85 85 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 255 255 255 255 85 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 255 85 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+170 85 0 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 170 85 0 85 85 85 255 255 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+255 85 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+170 85 0 85 85 85 255 255 85 255 255 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+170 85 0 170 85 0 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 170 85 0 170 85 0
+170 85 0 255 255 85 255 255 85 255 85 85 0 0 0 0 0 0
+85 85 85 85 85 85 85 85 85 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+85 85 85 170 85 0 170 85 0 170 85 0 255 255 85 255 255 85
+255 255 85 255 85 85 170 85 0 170 85 0 170 85 0 255 255 85
+255 255 85 255 255 85 255 85 85 170 170 170 0 0 0 0 0 0
+85 85 85 85 85 85 85 85 85 85 85 85 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+85 85 85 170 170 170 170 85 0 170 85 0 170 85 0 170 85 0
+170 85 0 170 85 0 170 85 0 255 255 85 255 255 85 255 255 85
+255 85 85 170 170 170 255 255 255 255 255 255 85 85 85 0 0 0
+0 0 0 85 85 85 85 85 85 85 85 85 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+170 170 170 170 170 170 170 170 170 170 85 0 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 85 85 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0
+0 0 0 0 0 0 85 85 85 85 85 85 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+170 170 170 255 255 255 255 255 255 170 170 170 170 85 0 255 85 85
+255 85 85 255 85 85 255 85 85 255 85 85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+170 170 170 255 255 255 255 255 255 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 85 85 85 0 0 0 0 0 0
+255 255 255 255 255 255 255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 0 0 0 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+85 85 85 0 0 0 0 0 0 85 85 85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 170 170 170 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 255 255 255 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 170 170 170
+170 170 170 170 170 170 170 170 170 255 255 255 0 0 0 85 85 85
+85 85 85 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255 255 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 0 0 0 85 85 85
+0 0 0 170 170 170 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 85 85 85 170 170 170 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170 255 255 255 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 85 85 85 0 0 0
+0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+170 170 170 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 85 85 85 0 0 0
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 170 170 170
+0 0 0 85 85 85 0 0 0 85 85 85 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 85 85 85 85 85 85 85 85 85
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 85 85 85 0 0 0 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+170 170 170 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 170 170 170 255 255 255 255 255 255 255 255 255 255 255 255
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 85 85 85 0 0 0 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 255 255 255 255 255 255 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 170 170 170
+170 170 170 0 0 0 0 0 0 85 85 85 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 85 85 85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 170 170 170 255 255 255 255 255 255
+170 170 170 0 0 0 0 0 0 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 85 0
+255 255 85 255 255 85 0 0 0 85 85 85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170 170 170 170 170 170 170 85 85 85 0 0 0 85 85 85
+85 85 85 85 85 85 0 0 0 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 85 85 85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 85 170 170 170
+85 85 85 170 170 170 170 170 170 85 85 85 0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 0 0 0 0 0 0 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+85 85 85 0 0 0 0 0 0 170 85 0 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 170 85 0 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170 170 170 170 170 170 170
+255 255 255 85 85 85 0 0 0 170 170 170 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 0 0 0 255 255 85 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 170 170
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+170 170 170 0 0 0 85 85 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 0 0 0
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 85 85 85 0 0 0
+0 0 0 0 0 0 85 85 85 255 255 255 255 255 255 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 0 0 0 0 0 0 255 255 85 255 255 85 255 255 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 170 170
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+170 170 170 170 170 170 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+0 0 0 170 170 170 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0
+0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 170 170 170
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 170 170 170
+85 85 85 0 0 0 255 255 85 255 255 85 255 255 85 255 255 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 170 170
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+170 170 170 170 170 170 170 170 170 170 170 170 255 255 85 255 255 85
+255 255 85 255 255 85 170 170 170 170 170 170 170 170 170 170 170 170
+255 255 85 85 85 85 170 170 170 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 170 170 170 170 170 170 170 170 170 255 255 255
+255 255 255 170 170 170 170 170 170 255 255 255 0 0 0 0 0 0
+0 0 0 85 85 85 255 255 255 255 255 255 255 255 255 85 85 85
+85 85 85 170 170 170 170 170 170 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+170 170 170 170 170 170 255 255 85 255 255 85 255 255 85 255 255 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 0 0 0 255 255 255 85 85 85 0 0 0 0 0 0
+255 255 255 85 85 85 0 0 0 0 0 0 255 255 255 255 255 85
+255 255 85 170 170 170 0 0 0 0 0 0 0 0 0 170 170 170
+255 255 255 170 170 170 85 85 85 0 0 0 0 0 0 0 0 0
+170 170 170 255 255 255 85 85 85 0 0 0 85 85 85 255 255 255
+85 85 85 0 0 0 85 85 85 255 255 255 0 0 0 0 0 0
+0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 85 85 85 0 0 0 0 0 0 85 85 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 255 255 255 255 255 85 255 255 85 255 255 85 255 255 85
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 170 170 170 0 0 0
+0 0 0 85 85 85 255 255 255 0 0 0 0 0 0 85 85 85
+255 255 255 0 0 0 0 0 0 85 85 85 255 255 85 255 255 85
+255 255 85 85 85 85 0 0 0 0 0 0 0 0 0 170 170 170
+255 255 255 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 255 255 255 0 0 0 0 0 0 170 170 170 170 170 170
+0 0 0 0 0 0 255 255 255 255 255 255 0 0 0 85 85 85
+255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 85 85 85 0 0 0 85 85 85 255 255 255 255 255 255
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 255 255 255 255 255 85 255 255 85 255 255 85
+255 255 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 170 170 170 0 0 0
+0 0 0 85 85 85 170 170 170 0 0 0 0 0 0 170 170 170
+170 170 170 0 0 0 0 0 0 170 170 170 255 255 85 255 255 85
+255 255 255 0 0 0 85 85 85 85 85 85 0 0 0 170 170 170
+255 255 255 0 0 0 0 0 0 170 170 170 85 85 85 0 0 0
+85 85 85 170 170 170 0 0 0 0 0 0 170 170 170 0 0 0
+0 0 0 170 170 170 255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255 170 170 170 170 170 170
+85 85 85 0 0 0 85 85 85 255 255 255 255 255 255 170 170 170
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 255 255 255 255 255 85 255 255 85
+255 255 85 170 85 0 0 0 0 85 85 85 85 85 85 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 255 255 255
+170 170 170 0 0 0 0 0 0 170 170 170 255 255 85 255 255 85
+170 170 170 0 0 0 170 170 170 85 85 85 0 0 0 255 255 255
+170 170 170 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0
+170 170 170 170 170 170 0 0 0 0 0 0 85 85 85 0 0 0
+85 85 85 255 255 255 255 255 255 255 255 255 255 255 255 170 170 170
+255 255 255 255 255 255 255 255 255 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 255 255 255 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 255 255 255 255 255 85
+255 255 85 255 255 85 255 255 255 170 170 170 170 170 170 255 255 255
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255
+85 85 85 0 0 0 0 0 0 255 255 255 255 255 85 255 255 85
+85 85 85 0 0 0 255 255 255 85 85 85 0 0 0 255 255 255
+85 85 85 0 0 0 85 85 85 255 255 255 85 85 85 85 85 85
+255 255 255 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+255 255 255 255 255 255 255 255 255 170 170 170 0 0 0 85 85 85
+255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255
+255 255 85 255 255 85 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 255 255 255
+0 0 0 0 0 0 85 85 85 255 255 85 255 255 85 255 255 255
+0 0 0 85 85 85 255 255 255 0 0 0 85 85 85 255 255 255
+85 85 85 0 0 0 170 170 170 255 255 255 170 170 170 170 170 170
+255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+255 255 255 255 255 255 255 255 255 170 170 170 0 0 0 170 170 170
+255 255 255 255 255 255 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 255 255 255
+170 170 170 0 0 0 85 85 85 85 85 85 0 0 0 170 170 170
+255 255 85 255 255 85 255 255 255 170 170 170 170 170 170 170 170 170
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 170 170 170 0 0 0 0 0 0
+85 85 85 170 170 170 0 0 0 0 0 0 85 85 85 170 170 170
+0 0 0 0 0 0 170 170 170 255 255 85 255 255 85 170 170 170
+0 0 0 85 85 85 170 170 170 0 0 0 85 85 85 255 255 255
+0 0 0 0 0 0 170 170 170 170 170 170 170 170 170 255 255 255
+170 170 170 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+255 255 255 255 255 255 255 255 255 85 85 85 0 0 0 255 255 255
+255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 255 255 255 255 255 85 255 255 255
+85 85 85 170 170 170 255 255 255 255 255 255 170 170 170 0 0 0
+170 170 170 255 255 85 255 255 85 255 255 255 170 170 170 255 255 255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 170 170 170 0 0 0 0 0 0
+170 170 170 170 170 170 0 0 0 0 0 0 85 85 85 170 170 170
+0 0 0 0 0 0 170 170 170 255 255 85 255 255 255 85 85 85
+0 0 0 85 85 85 85 85 85 0 0 0 85 85 85 170 170 170
+0 0 0 0 0 0 255 255 255 85 85 85 0 0 0 170 170 170
+170 170 170 0 0 0 0 0 0 85 85 85 0 0 0 85 85 85
+255 255 255 255 255 255 255 255 255 85 85 85 85 85 85 255 255 255
+255 255 255 85 85 85 0 0 0 0 0 0 0 0 0 170 170 170
+170 170 170 170 170 170 255 255 255 0 0 0 0 0 0 0 0 0
+0 0 0 170 170 170 255 255 255 255 255 255 255 255 85 170 170 170
+255 255 255 255 255 255 255 255 85 255 255 85 170 170 170 0 0 0
+0 0 0 170 170 170 255 255 85 255 255 85 255 255 85 255 255 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 85 85 85 0 0 0 0 0 0
+255 255 255 85 85 85 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 0 0 0 255 255 255 255 255 85 255 255 255 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 85 85 85 255 255 255 0 0 0 0 0 0 255 255 255
+85 85 85 0 0 0 85 85 85 85 85 85 0 0 0 0 0 0
+255 255 255 255 255 255 255 255 255 85 85 85 170 170 170 255 255 255
+255 255 255 0 0 0 0 0 0 0 0 0 170 170 170 255 255 255
+170 170 170 85 85 85 170 170 170 0 0 0 0 0 0 85 85 85
+255 255 255 170 170 170 0 0 0 170 170 170 255 255 85 255 255 255
+255 255 255 170 170 170 255 255 255 255 255 255 85 85 85 0 0 0
+85 85 85 255 255 255 255 255 255 255 255 85 255 255 85 255 255 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 0 0 0 0 0 0 0 0 0
+85 85 85 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0
+0 0 0 85 85 85 170 170 170 255 255 255 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 85 85 85 170 170 170 0 0 0 85 85 85 255 255 255
+0 0 0 0 0 0 170 170 170 170 170 170 0 0 0 0 0 0
+255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255
+170 170 170 0 0 0 0 0 0 170 170 170 255 255 255 85 85 85
+170 170 170 170 170 170 170 170 170 0 0 0 85 85 85 255 255 255
+170 170 170 0 0 0 85 85 85 255 255 255 255 255 85 170 170 170
+0 0 0 170 170 170 255 255 255 255 255 255 0 0 0 85 85 85
+255 255 255 170 170 170 0 0 0 170 170 170 255 255 85 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 85 85 85 0 0 0
+170 170 170 255 255 255 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 170 170 170
+0 0 0 0 0 0 255 255 255 170 170 170 0 0 0 0 0 0
+255 255 255 255 255 255 170 170 170 85 85 85 255 255 255 255 255 255
+85 85 85 0 0 0 170 170 170 170 170 170 0 0 0 0 0 0
+170 170 170 170 170 170 255 255 255 255 255 255 255 255 255 85 85 85
+0 0 0 0 0 0 255 255 255 255 255 255 170 170 170 0 0 0
+0 0 0 170 170 170 255 255 255 170 170 170 170 170 170 255 255 255
+85 85 85 0 0 0 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 255 255 255 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0
+255 255 255 255 255 255 0 0 0 0 0 0 255 255 255 170 170 170
+0 0 0 0 0 0 0 0 0 170 170 170 255 255 255 170 170 170
+0 0 0 0 0 0 255 255 255 170 170 170 0 0 0 0 0 0
+170 170 170 255 255 255 170 170 170 170 170 170 170 170 170 170 170 170
+0 0 0 85 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+85 85 85 255 255 255 255 255 255 170 170 170 0 0 0 0 0 0
+0 0 0 170 170 170 255 255 255 170 170 170 0 0 0 0 0 0
+85 85 85 255 255 255 255 255 85 255 255 255 255 255 255 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 170 170
+85 85 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 255 255 85 255 255 85 255 255 85 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+255 255 85 170 170 170 170 170 170 170 170 170 255 255 85 255 255 85
+170 170 170 170 170 170 170 170 170 255 255 85 255 255 85 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 85 85 85 170 170 170 170 170 170 170 170 170
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 255 255 255 170 170 170 0 0 0 0 0 0 0 0 0
+0 0 0 255 255 255 255 255 255 255 255 255 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+170 170 170 85 85 85 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 85 85 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 85 85 85 85 85 0 0 0 0 0 0 0 0 0
+85 85 85 170 170 170 85 85 85 170 170 170 170 170 170 85 85 85
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 170 170 170 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 170 170 170 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+85 85 85 170 170 170 85 85 85 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 85 85 85 85 85 85 170 85 0 170 85 0
+170 85 0 255 85 85 255 85 85 255 85 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 85 85 170 85 0 85 85 85 0 0 0 0 0 0 85 85 85
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 170 170 170 170 170 170 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 85 85
+85 85 85 85 85 85 170 85 0 170 85 0 170 85 0 170 85 0
+255 85 85 255 85 85 255 255 85 255 255 85 255 255 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 255 85 255 85 85
+170 85 0 170 85 0 0 0 0 85 85 85 85 85 85 170 170 170
+170 170 170 0 0 0 170 170 170 255 255 255 170 170 170 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 170 170 170 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 85 85 85
+170 85 0 170 85 0 170 85 0 255 85 85 255 85 85 255 255 85
+255 255 85 255 255 85 255 255 85 255 255 85 255 85 85 170 85 0
+170 85 0 85 85 85 85 85 85 85 85 85 170 170 170 170 170 170
+0 0 0 0 0 0 255 255 255 255 255 255 85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 170 170 170 85 85 85 0 0 0
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 170 85 0 170 85 0 170 85 0
+170 85 0 255 85 85 255 85 85 255 85 85 170 85 0 170 85 0
+85 85 85 0 0 0 0 0 0 85 85 85 170 170 170 0 0 0
+0 0 0 85 85 85 255 255 255 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 170 170 170 85 85 85
+0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 85 85 85
+170 85 0 170 85 0 170 85 0 170 85 0 170 85 0 85 85 85
+0 0 0 0 0 0 0 0 0 85 85 85 170 170 170 0 0 0
+0 0 0 85 85 85 255 255 255 170 170 170 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 85 85 85 170 170 170
+85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 85 85 85 85 85 85 85 85 85 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 85 85 85 85 85 85 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170 170 170 170 85 85 85
+85 85 85 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index aaa3e538e5da..5b5f072fc1a8 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -522,8 +522,6 @@ static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) {
#endif
}
-#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x))))
-#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x))))
static int parse_pins1(WPMINFO const struct matrox_bios* bd) {
unsigned int maxdac;
@@ -532,11 +530,12 @@ static int parse_pins1(WPMINFO const struct matrox_bios* bd) {
case 1: maxdac = 220000; break;
default: maxdac = 240000; break;
}
- if (get_u16(bd->pins + 24)) {
- maxdac = get_u16(bd->pins + 24) * 10;
+ if (get_unaligned_le16(bd->pins + 24)) {
+ maxdac = get_unaligned_le16(bd->pins + 24) * 10;
}
MINFO->limits.pixel.vcomax = maxdac;
- MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000;
+ MINFO->values.pll.system = get_unaligned_le16(bd->pins + 28) ?
+ get_unaligned_le16(bd->pins + 28) * 10 : 50000;
/* ignore 4MB, 8MB, module clocks */
MINFO->features.pll.ref_freq = 14318;
MINFO->values.reg.mctlwtst = 0x00030101;
@@ -575,7 +574,8 @@ static void default_pins2(WPMINFO2) {
static int parse_pins3(WPMINFO const struct matrox_bios* bd) {
MINFO->limits.pixel.vcomax =
MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000);
- MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48);
+ MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ?
+ 0x01250A21 : get_unaligned_le32(bd->pins + 48);
/* memory config */
MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) |
((bd->pins[57] << 22) & 0x00C00000) |
@@ -601,7 +601,7 @@ static void default_pins3(WPMINFO2) {
static int parse_pins4(WPMINFO const struct matrox_bios* bd) {
MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000;
MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000;
- MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71);
+ MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 71);
MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) |
((bd->pins[87] << 22) & 0x00C00000) |
((bd->pins[86] << 1) & 0x000001E0) |
@@ -609,7 +609,7 @@ static int parse_pins4(WPMINFO const struct matrox_bios* bd) {
MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) |
((bd->pins[53] << 22) & 0x10000000) |
((bd->pins[53] << 7) & 0x00001C00);
- MINFO->values.reg.opt3 = get_u32(bd->pins + 67);
+ MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 67);
MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000;
MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000;
return 0;
@@ -640,12 +640,12 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) {
MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult;
MINFO->values.pll.system =
MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000;
- MINFO->values.reg.opt = get_u32(bd->pins+ 48);
- MINFO->values.reg.opt2 = get_u32(bd->pins+ 52);
- MINFO->values.reg.opt3 = get_u32(bd->pins+ 94);
- MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98);
- MINFO->values.reg.memmisc = get_u32(bd->pins+102);
- MINFO->values.reg.memrdbk = get_u32(bd->pins+106);
+ MINFO->values.reg.opt = get_unaligned_le32(bd->pins + 48);
+ MINFO->values.reg.opt2 = get_unaligned_le32(bd->pins + 52);
+ MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 94);
+ MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 98);
+ MINFO->values.reg.memmisc = get_unaligned_le32(bd->pins + 102);
+ MINFO->values.reg.memrdbk = get_unaligned_le32(bd->pins + 106);
MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000;
MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20;
MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0;
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index 249791286367..cc4c038a1b3f 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -206,8 +206,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
}
/* check waveform mode table address checksum */
- wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta));
- wmta &= 0x00FFFFFF;
+ wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
cksum_idx = wmta + m*4 + 3;
if (cksum_idx > size)
return -EINVAL;
@@ -219,8 +218,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
}
/* check waveform temperature table address checksum */
- tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4)));
- tta &= 0x00FFFFFF;
+ tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
cksum_idx = tta + trn*4 + 3;
if (cksum_idx > size)
return -EINVAL;
@@ -233,8 +231,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
/* here we do the real work of putting the waveform into the
metromem buffer. this does runlength decoding of the waveform */
- wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4)));
- wfm_idx &= 0x00FFFFFF;
+ wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
owfm_idx = wfm_idx;
if (wfm_idx > size)
return -EINVAL;
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index c95874fe9076..9e903454ffc1 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -15,10 +15,9 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -275,7 +274,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
par->physbase = op->resource[2].start;
par->which_io = op->resource[2].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&info->var, dp->node, 8);
+ sbusfb_fill_var(&info->var, dp, 8);
info->var.red.length = 8;
info->var.green.length = 8;
info->var.blue.length = 8;
@@ -295,7 +294,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
if (!info->screen_base)
goto out_unmap_regs;
- p9100_blank(0, info);
+ p9100_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_screen;
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
index 685761a0732c..4db6b48a8715 100644
--- a/drivers/video/pnx4008/pnxrgbfb.c
+++ b/drivers/video/pnx4008/pnxrgbfb.c
@@ -100,7 +100,6 @@ static int rgbfb_remove(struct platform_device *pdev)
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
platform_set_drvdata(pdev, NULL);
- kfree(info);
}
pnx4008_free_dum_channel(channel_owned, pdev->id);
@@ -168,23 +167,21 @@ static int __devinit rgbfb_probe(struct platform_device *pdev)
ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret < 0)
- goto err2;
+ goto err1;
ret = register_framebuffer(info);
if (ret < 0)
- goto err3;
+ goto err2;
platform_set_drvdata(pdev, info);
return 0;
-err3:
- fb_dealloc_cmap(&info->cmap);
err2:
- framebuffer_release(info);
+ fb_dealloc_cmap(&info->cmap);
err1:
pnx4008_free_dum_channel(channel_owned, pdev->id);
err0:
- kfree(info);
+ framebuffer_release(info);
err:
return ret;
}
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 757651954e6c..3ee314beacc1 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -39,6 +39,9 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -57,19 +60,31 @@
#include "pxafb.h"
/* Bits which should not be set in machine configuration structures */
-#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
-#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
+#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM | LCCR0_BM | LCCR0_QDM |\
+ LCCR0_DIS | LCCR0_EFM | LCCR0_IUM |\
+ LCCR0_SFM | LCCR0_LDM | LCCR0_ENB)
+
+#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP | LCCR3_VSP |\
+ LCCR3_PCD | LCCR3_BPP)
static void (*pxafb_backlight_power)(int);
static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
-static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+static int pxafb_activate_var(struct fb_var_screeninfo *var,
+ struct pxafb_info *);
static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
-#ifdef CONFIG_FB_PXA_PARAMETERS
-#define PXAFB_OPTIONS_SIZE 256
-static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
-#endif
+static inline unsigned long
+lcd_readl(struct pxafb_info *fbi, unsigned int off)
+{
+ return __raw_readl(fbi->mmio_base + off);
+}
+
+static inline void
+lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
+{
+ __raw_writel(val, fbi->mmio_base + off);
+}
static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
{
@@ -79,10 +94,12 @@ static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
/*
* We need to handle two requests being made at the same time.
* There are two important cases:
- * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
- * We must perform the unblanking, which will do our REENABLE for us.
- * 2. When we are blanking, but immediately unblank before we have
- * blanked. We do the "REENABLE" thing here as well, just to be sure.
+ * 1. When we are changing VT (C_REENABLE) while unblanking
+ * (C_ENABLE) We must perform the unblanking, which will
+ * do our REENABLE for us.
+ * 2. When we are blanking, but immediately unblank before
+ * we have blanked. We do the "REENABLE" thing here as
+ * well, just to be sure.
*/
if (fbi->task_state == C_ENABLE && state == C_REENABLE)
state = (u_int) -1;
@@ -129,13 +146,13 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
val = ((red << 8) & 0x00f80000);
val |= ((green >> 0) & 0x0000fc00);
val |= ((blue >> 8) & 0x000000f8);
- ((u32*)(fbi->palette_cpu))[regno] = val;
+ ((u32 *)(fbi->palette_cpu))[regno] = val;
break;
case LCCR4_PAL_FOR_2:
val = ((red << 8) & 0x00fc0000);
val |= ((green >> 0) & 0x0000fc00);
val |= ((blue >> 8) & 0x000000fc);
- ((u32*)(fbi->palette_cpu))[regno] = val;
+ ((u32 *)(fbi->palette_cpu))[regno] = val;
break;
}
@@ -203,15 +220,15 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
*/
static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
{
- int ret = 0;
- switch (var->bits_per_pixel) {
- case 1: ret = LCCR3_1BPP; break;
- case 2: ret = LCCR3_2BPP; break;
- case 4: ret = LCCR3_4BPP; break;
- case 8: ret = LCCR3_8BPP; break;
- case 16: ret = LCCR3_16BPP; break;
- }
- return ret;
+ int ret = 0;
+ switch (var->bits_per_pixel) {
+ case 1: ret = LCCR3_1BPP; break;
+ case 2: ret = LCCR3_2BPP; break;
+ case 4: ret = LCCR3_4BPP; break;
+ case 8: ret = LCCR3_8BPP; break;
+ case 16: ret = LCCR3_16BPP; break;
+ }
+ return ret;
}
#ifdef CONFIG_CPU_FREQ
@@ -223,31 +240,32 @@ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
*/
static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
{
- /*
- * Period = pixclock * bits_per_byte * bytes_per_transfer
- * / memory_bits_per_pixel;
- */
- return var->pixclock * 8 * 16 / var->bits_per_pixel;
+ /*
+ * Period = pixclock * bits_per_byte * bytes_per_transfer
+ * / memory_bits_per_pixel;
+ */
+ return var->pixclock * 8 * 16 / var->bits_per_pixel;
}
-
-extern unsigned int get_clk_frequency_khz(int info);
#endif
/*
* Select the smallest mode that allows the desired resolution to be
* displayed. If desired parameters can be rounded up.
*/
-static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
+static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach,
+ struct fb_var_screeninfo *var)
{
struct pxafb_mode_info *mode = NULL;
struct pxafb_mode_info *modelist = mach->modes;
unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
unsigned int i;
- for (i = 0 ; i < mach->num_modes ; i++) {
- if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
- modelist[i].xres < best_x && modelist[i].yres < best_y &&
- modelist[i].bpp >= var->bits_per_pixel ) {
+ for (i = 0; i < mach->num_modes; i++) {
+ if (modelist[i].xres >= var->xres &&
+ modelist[i].yres >= var->yres &&
+ modelist[i].xres < best_x &&
+ modelist[i].yres < best_y &&
+ modelist[i].bpp >= var->bits_per_pixel) {
best_x = modelist[i].xres;
best_y = modelist[i].yres;
mode = &modelist[i];
@@ -257,7 +275,8 @@ static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struc
return mode;
}
-static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
+static void pxafb_setmode(struct fb_var_screeninfo *var,
+ struct pxafb_mode_info *mode)
{
var->xres = mode->xres;
var->yres = mode->yres;
@@ -315,19 +334,20 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->yres_virtual =
max(var->yres_virtual, var->yres);
- /*
+ /*
* Setup the RGB parameters for this display.
*
* The pixel packing format is described on page 7-11 of the
* PXA2XX Developer's Manual.
- */
+ */
if (var->bits_per_pixel == 16) {
var->red.offset = 11; var->red.length = 5;
var->green.offset = 5; var->green.length = 6;
var->blue.offset = 0; var->blue.length = 5;
var->transp.offset = var->transp.length = 0;
} else {
- var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
+ var->red.offset = var->green.offset = 0;
+ var->blue.offset = var->transp.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
@@ -335,9 +355,8 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
#ifdef CONFIG_CPU_FREQ
- pr_debug("pxafb: dma period = %d ps, clock = %d kHz\n",
- pxafb_display_dma_period(var),
- get_clk_frequency_khz(0));
+ pr_debug("pxafb: dma period = %d ps\n",
+ pxafb_display_dma_period(var));
#endif
return 0;
@@ -345,8 +364,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static inline void pxafb_set_truecolor(u_int is_true_color)
{
- pr_debug("pxafb: true_color = %d\n", is_true_color);
- // do your machine-specific setup if needed
+ /* do your machine-specific setup if needed */
}
/*
@@ -357,9 +375,6 @@ static int pxafb_set_par(struct fb_info *info)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
struct fb_var_screeninfo *var = &info->var;
- unsigned long palette_mem_size;
-
- pr_debug("pxafb: set_par\n");
if (var->bits_per_pixel == 16)
fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
@@ -379,17 +394,10 @@ static int pxafb_set_par(struct fb_info *info)
if (var->bits_per_pixel == 16)
fbi->palette_size = 0;
else
- fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
-
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- palette_mem_size = fbi->palette_size * sizeof(u16);
- else
- palette_mem_size = fbi->palette_size * sizeof(u32);
-
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
+ fbi->palette_size = var->bits_per_pixel == 1 ?
+ 4 : 1 << var->bits_per_pixel;
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+ fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0];
/*
* Set (any) board control register to handle new color depth
@@ -407,36 +415,6 @@ static int pxafb_set_par(struct fb_info *info)
}
/*
- * Formal definition of the VESA spec:
- * On
- * This refers to the state of the display when it is in full operation
- * Stand-By
- * This defines an optional operating state of minimal power reduction with
- * the shortest recovery time
- * Suspend
- * This refers to a level of power management in which substantial power
- * reduction is achieved by the display. The display can have a longer
- * recovery time from this state than from the Stand-by state
- * Off
- * This indicates that the display is consuming the lowest level of power
- * and is non-operational. Recovery from this state may optionally require
- * the user to manually power on the monitor
- *
- * Now, the fbdev driver adds an additional state, (blank), where they
- * turn off the video (maybe by colormap tricks), but don't mess with the
- * video itself: think of it semantically between on and Stand-By.
- *
- * So here's what we should do in our fbdev blank routine:
- *
- * VESA_NO_BLANKING (mode 0) Video on, front/back light on
- * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off
- * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off
- * VESA_POWERDOWN (mode 3) Video off, front/back light off
- *
- * This will match the matrox implementation.
- */
-
-/*
* pxafb_blank():
* Blank the display by setting all palette values to zero. Note, the
* 16 bpp mode does not really use the palette, so this will not
@@ -447,8 +425,6 @@ static int pxafb_blank(int blank, struct fb_info *info)
struct pxafb_info *fbi = (struct pxafb_info *)info;
int i;
- pr_debug("pxafb: blank=%d\n", blank);
-
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_VSYNC_SUSPEND:
@@ -460,11 +436,11 @@ static int pxafb_blank(int blank, struct fb_info *info)
pxafb_setpalettereg(i, 0, 0, 0, 0, info);
pxafb_schedule_work(fbi, C_DISABLE);
- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
break;
case FB_BLANK_UNBLANK:
- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&fbi->fb.cmap, info);
@@ -480,7 +456,7 @@ static int pxafb_mmap(struct fb_info *info,
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
- vma->vm_pgoff += 1;
+ vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
@@ -529,7 +505,8 @@ static struct fb_ops pxafb_ops = {
*
* Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
*/
-static inline unsigned int get_pcd(struct pxafb_info *fbi, unsigned int pixclock)
+static inline unsigned int get_pcd(struct pxafb_info *fbi,
+ unsigned int pixclock)
{
unsigned long long pcd;
@@ -555,7 +532,7 @@ static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd)
unsigned long htime;
if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
- fbi->hsync_time=0;
+ fbi->hsync_time = 0;
return;
}
@@ -576,71 +553,231 @@ unsigned long pxafb_get_hsync_time(struct device *dev)
}
EXPORT_SYMBOL(pxafb_get_hsync_time);
-/*
- * pxafb_activate_var():
- * Configures LCD Controller based on entries in var parameter. Settings are
- * only written to the controller if changes were made.
- */
-static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
+static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
+ unsigned int offset, size_t size)
{
- struct pxafb_lcd_reg new_regs;
- u_long flags;
- u_int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+ struct pxafb_dma_descriptor *dma_desc, *pal_desc;
+ unsigned int dma_desc_off, pal_desc_off;
- pr_debug("pxafb: Configuring PXA LCD\n");
+ if (dma < 0 || dma >= DMA_MAX)
+ return -EINVAL;
- pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
- var->xres, var->hsync_len,
- var->left_margin, var->right_margin);
- pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
- var->yres, var->vsync_len,
- var->upper_margin, var->lower_margin);
- pr_debug("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
+ dma_desc = &fbi->dma_buff->dma_desc[dma];
+ dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]);
-#if DEBUG_VAR
- if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d\n",
- fbi->fb.fix.id, var->xres);
- switch(var->bits_per_pixel) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- break;
- default:
- printk(KERN_ERR "%s: invalid bit depth %d\n",
- fbi->fb.fix.id, var->bits_per_pixel);
- break;
+ dma_desc->fsadr = fbi->screen_dma + offset;
+ dma_desc->fidr = 0;
+ dma_desc->ldcmd = size;
+
+ if (pal < 0 || pal >= PAL_MAX) {
+ dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
+ } else {
+ pal_desc = &fbi->dma_buff->pal_desc[dma];
+ pal_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[pal]);
+
+ pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE;
+ pal_desc->fidr = 0;
+
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ pal_desc->ldcmd = fbi->palette_size * sizeof(u16);
+ else
+ pal_desc->ldcmd = fbi->palette_size * sizeof(u32);
+
+ pal_desc->ldcmd |= LDCMD_PAL;
+
+ /* flip back and forth between palette and frame buffer */
+ pal_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ dma_desc->fdadr = fbi->dma_buff_phys + pal_desc_off;
+ fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
}
- if (var->hsync_len < 1 || var->hsync_len > 64)
- printk(KERN_ERR "%s: invalid hsync_len %d\n",
- fbi->fb.fix.id, var->hsync_len);
- if (var->left_margin < 1 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d\n",
- fbi->fb.fix.id, var->left_margin);
- if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d\n",
- fbi->fb.fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 1024)
- printk(KERN_ERR "%s: invalid yres %d\n",
- fbi->fb.fix.id, var->yres);
- if (var->vsync_len < 1 || var->vsync_len > 64)
- printk(KERN_ERR "%s: invalid vsync_len %d\n",
- fbi->fb.fix.id, var->vsync_len);
- if (var->upper_margin < 0 || var->upper_margin > 255)
- printk(KERN_ERR "%s: invalid upper_margin %d\n",
- fbi->fb.fix.id, var->upper_margin);
- if (var->lower_margin < 0 || var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d\n",
- fbi->fb.fix.id, var->lower_margin);
-#endif
- new_regs.lccr0 = fbi->lccr0 |
- (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
- LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
+ return 0;
+}
+
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+static int setup_smart_dma(struct pxafb_info *fbi)
+{
+ struct pxafb_dma_descriptor *dma_desc;
+ unsigned long dma_desc_off, cmd_buff_off;
+
+ dma_desc = &fbi->dma_buff->dma_desc[DMA_CMD];
+ dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[DMA_CMD]);
+ cmd_buff_off = offsetof(struct pxafb_dma_buff, cmd_buff);
+
+ dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ dma_desc->fsadr = fbi->dma_buff_phys + cmd_buff_off;
+ dma_desc->fidr = 0;
+ dma_desc->ldcmd = fbi->n_smart_cmds * sizeof(uint16_t);
+
+ fbi->fdadr[DMA_CMD] = dma_desc->fdadr;
+ return 0;
+}
+
+int pxafb_smart_flush(struct fb_info *info)
+{
+ struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
+ uint32_t prsr;
+ int ret = 0;
+
+ /* disable controller until all registers are set up */
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+
+ /* 1. make it an even number of commands to align on 32-bit boundary
+ * 2. add the interrupt command to the end of the chain so we can
+ * keep track of the end of the transfer
+ */
+
+ while (fbi->n_smart_cmds & 1)
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_NOOP;
+
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_INTERRUPT;
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_WAIT_FOR_VSYNC;
+ setup_smart_dma(fbi);
+
+ /* continue to execute next command */
+ prsr = lcd_readl(fbi, PRSR) | PRSR_ST_OK | PRSR_CON_NT;
+ lcd_writel(fbi, PRSR, prsr);
+
+ /* stop the processor in case it executed "wait for sync" cmd */
+ lcd_writel(fbi, CMDCR, 0x0001);
+
+ /* don't send interrupts for fifo underruns on channel 6 */
+ lcd_writel(fbi, LCCR5, LCCR5_IUM(6));
+
+ lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
+ lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
+ lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+ lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
+ lcd_writel(fbi, FDADR6, fbi->fdadr[6]);
+
+ /* begin sending */
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
+
+ if (wait_for_completion_timeout(&fbi->command_done, HZ/2) == 0) {
+ pr_warning("%s: timeout waiting for command done\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ /* quick disable */
+ prsr = lcd_readl(fbi, PRSR) & ~(PRSR_ST_OK | PRSR_CON_NT);
+ lcd_writel(fbi, PRSR, prsr);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+ lcd_writel(fbi, FDADR6, 0);
+ fbi->n_smart_cmds = 0;
+ return ret;
+}
+
+int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
+{
+ int i;
+ struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
+
+ /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */
+ for (i = 0; i < n_cmds; i++) {
+ if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8)
+ pxafb_smart_flush(info);
+
+ fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds++;
+ }
+
+ return 0;
+}
+
+static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk)
+{
+ unsigned int t = (time_ns * (lcd_clk / 1000000) / 1000);
+ return (t == 0) ? 1 : t;
+}
+
+static void setup_smart_timing(struct pxafb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+ struct pxafb_mode_info *mode = &inf->modes[0];
+ unsigned long lclk = clk_get_rate(fbi->clk);
+ unsigned t1, t2, t3, t4;
+
+ t1 = max(mode->a0csrd_set_hld, mode->a0cswr_set_hld);
+ t2 = max(mode->rd_pulse_width, mode->wr_pulse_width);
+ t3 = mode->op_hold_time;
+ t4 = mode->cmd_inh_time;
+
+ fbi->reg_lccr1 =
+ LCCR1_DisWdth(var->xres) |
+ LCCR1_BegLnDel(__smart_timing(t1, lclk)) |
+ LCCR1_EndLnDel(__smart_timing(t2, lclk)) |
+ LCCR1_HorSnchWdth(__smart_timing(t3, lclk));
+
+ fbi->reg_lccr2 = LCCR2_DisHght(var->yres);
+ fbi->reg_lccr3 = LCCR3_PixClkDiv(__smart_timing(t4, lclk));
+
+ /* FIXME: make this configurable */
+ fbi->reg_cmdcr = 1;
+}
+
+static int pxafb_smart_thread(void *arg)
+{
+ struct pxafb_info *fbi = arg;
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+
+ if (!fbi || !inf->smart_update) {
+ pr_err("%s: not properly initialized, thread terminated\n",
+ __func__);
+ return -EINVAL;
+ }
- new_regs.lccr1 =
+ pr_debug("%s(): task starting\n", __func__);
+
+ set_freezable();
+ while (!kthread_should_stop()) {
+
+ if (try_to_freeze())
+ continue;
+
+ if (fbi->state == C_ENABLE) {
+ inf->smart_update(&fbi->fb);
+ complete(&fbi->refresh_done);
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(30 * HZ / 1000);
+ }
+
+ pr_debug("%s(): task ending\n", __func__);
+ return 0;
+}
+
+static int pxafb_smart_init(struct pxafb_info *fbi)
+{
+ fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi,
+ "lcd_refresh");
+ if (IS_ERR(fbi->smart_thread)) {
+ printk(KERN_ERR "%s: unable to create kernel thread\n",
+ __func__);
+ return PTR_ERR(fbi->smart_thread);
+ }
+ return 0;
+}
+#else
+int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
+{
+ return 0;
+}
+
+int pxafb_smart_flush(struct fb_info *info)
+{
+ return 0;
+}
+#endif /* CONFIG_FB_SMART_PANEL */
+
+static void setup_parallel_timing(struct pxafb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ unsigned int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+
+ fbi->reg_lccr1 =
LCCR1_DisWdth(var->xres) +
LCCR1_HorSnchWdth(var->hsync_len) +
LCCR1_BegLnDel(var->left_margin) +
@@ -654,110 +791,118 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
lines_per_panel /= 2;
- new_regs.lccr2 =
+ fbi->reg_lccr2 =
LCCR2_DisHght(lines_per_panel) +
LCCR2_VrtSnchWdth(var->vsync_len) +
LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin);
- new_regs.lccr3 = fbi->lccr3 |
- pxafb_bpp_to_lccr3(var) |
- (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
- (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+ fbi->reg_lccr3 = fbi->lccr3 |
+ (var->sync & FB_SYNC_HOR_HIGH_ACT ?
+ LCCR3_HorSnchH : LCCR3_HorSnchL) |
+ (var->sync & FB_SYNC_VERT_HIGH_ACT ?
+ LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+
+ if (pcd) {
+ fbi->reg_lccr3 |= LCCR3_PixClkDiv(pcd);
+ set_hsync_time(fbi, pcd);
+ }
+}
- if (pcd)
- new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+/*
+ * pxafb_activate_var():
+ * Configures LCD Controller based on entries in var parameter.
+ * Settings are only written to the controller if changes were made.
+ */
+static int pxafb_activate_var(struct fb_var_screeninfo *var,
+ struct pxafb_info *fbi)
+{
+ u_long flags;
+ size_t nbytes;
- pr_debug("nlccr0 = 0x%08x\n", new_regs.lccr0);
- pr_debug("nlccr1 = 0x%08x\n", new_regs.lccr1);
- pr_debug("nlccr2 = 0x%08x\n", new_regs.lccr2);
- pr_debug("nlccr3 = 0x%08x\n", new_regs.lccr3);
+#if DEBUG_VAR
+ if (!(fbi->lccr0 & LCCR0_LCDT)) {
+ if (var->xres < 16 || var->xres > 1024)
+ printk(KERN_ERR "%s: invalid xres %d\n",
+ fbi->fb.fix.id, var->xres);
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ printk(KERN_ERR "%s: invalid bit depth %d\n",
+ fbi->fb.fix.id, var->bits_per_pixel);
+ break;
+ }
+ if (var->hsync_len < 1 || var->hsync_len > 64)
+ printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ fbi->fb.fix.id, var->hsync_len);
+ if (var->left_margin < 1 || var->left_margin > 255)
+ printk(KERN_ERR "%s: invalid left_margin %d\n",
+ fbi->fb.fix.id, var->left_margin);
+ if (var->right_margin < 1 || var->right_margin > 255)
+ printk(KERN_ERR "%s: invalid right_margin %d\n",
+ fbi->fb.fix.id, var->right_margin);
+ if (var->yres < 1 || var->yres > 1024)
+ printk(KERN_ERR "%s: invalid yres %d\n",
+ fbi->fb.fix.id, var->yres);
+ if (var->vsync_len < 1 || var->vsync_len > 64)
+ printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ fbi->fb.fix.id, var->vsync_len);
+ if (var->upper_margin < 0 || var->upper_margin > 255)
+ printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ fbi->fb.fix.id, var->upper_margin);
+ if (var->lower_margin < 0 || var->lower_margin > 255)
+ printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ fbi->fb.fix.id, var->lower_margin);
+ }
+#endif
/* Update shadow copy atomically */
local_irq_save(flags);
- /* setup dma descriptors */
- fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
- fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
- fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
-
- fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
- fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
- fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
-
-#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length)
-
- /* populate descriptors */
- fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
- fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
- fbi->dmadesc_fblow_cpu->fidr = 0;
- fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (fbi->lccr0 & LCCR0_LCDT)
+ setup_smart_timing(fbi, var);
+ else
+#endif
+ setup_parallel_timing(fbi, var);
- fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
+ fbi->reg_lccr0 = fbi->lccr0 |
+ (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+ LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
- fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
- fbi->dmadesc_fbhigh_cpu->fidr = 0;
- fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
+ fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
- fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
- fbi->dmadesc_palette_cpu->fidr = 0;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
- sizeof(u16);
- else
- fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
- sizeof(u32);
- fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
+ nbytes = var->yres * fbi->fb.fix.line_length;
- if (var->bits_per_pixel == 16) {
- /* palette shouldn't be loaded in true-color mode */
- fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
- fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
- /* init it to something, even though we won't be using it */
- fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
- } else {
- fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
- fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
- fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
+ if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) {
+ nbytes = nbytes / 2;
+ setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes);
}
-#if 0
- pr_debug("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
- pr_debug("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
- pr_debug("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
- pr_debug("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
- pr_debug("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
- pr_debug("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
-
- pr_debug("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
- pr_debug("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
- pr_debug("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
-
- pr_debug("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
- pr_debug("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
- pr_debug("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
-
- pr_debug("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
- pr_debug("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
- pr_debug("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
-#endif
+ if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT))
+ setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes);
+ else
+ setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes);
- fbi->reg_lccr0 = new_regs.lccr0;
- fbi->reg_lccr1 = new_regs.lccr1;
- fbi->reg_lccr2 = new_regs.lccr2;
- fbi->reg_lccr3 = new_regs.lccr3;
- fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK);
+ fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK;
fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
- set_hsync_time(fbi, pcd);
local_irq_restore(flags);
/*
* Only update the registers if the controller is enabled
* and something has changed.
*/
- if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
- (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
- (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1))
+ if ((lcd_readl(fbi, LCCR0) != fbi->reg_lccr0) ||
+ (lcd_readl(fbi, LCCR1) != fbi->reg_lccr1) ||
+ (lcd_readl(fbi, LCCR2) != fbi->reg_lccr2) ||
+ (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
+ (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
+ (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
pxafb_schedule_work(fbi, C_REENABLE);
return 0;
@@ -773,8 +918,8 @@ static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
{
pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff");
- if (pxafb_backlight_power)
- pxafb_backlight_power(on);
+ if (pxafb_backlight_power)
+ pxafb_backlight_power(on);
}
static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
@@ -788,11 +933,11 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
static void pxafb_setup_gpio(struct pxafb_info *fbi)
{
int gpio, ldd_bits;
- unsigned int lccr0 = fbi->lccr0;
+ unsigned int lccr0 = fbi->lccr0;
/*
* setup is based on type of panel supported
- */
+ */
/* 4 bit interface */
if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
@@ -801,21 +946,25 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
ldd_bits = 4;
/* 8 bit interface */
- else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
- ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
- (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
+ else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
+ (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+ ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+ (lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+ (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
ldd_bits = 8;
/* 16 bit interface */
else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
+ (lccr0 & LCCR0_PAS) == LCCR0_Act))
ldd_bits = 16;
else {
- printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+ printk(KERN_ERR "pxafb_setup_gpio: unable to determine "
+ "bits per pixel\n");
return;
- }
+ }
for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
@@ -828,8 +977,8 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
static void pxafb_enable_controller(struct pxafb_info *fbi)
{
pr_debug("pxafb: Enabling LCD controller\n");
- pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
- pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+ pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr[0]);
+ pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr[1]);
pr_debug("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
pr_debug("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
pr_debug("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
@@ -838,40 +987,40 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
/* enable LCD controller clock */
clk_enable(fbi->clk);
+ if (fbi->lccr0 & LCCR0_LCDT)
+ return;
+
/* Sequence from 11.7.10 */
- LCCR3 = fbi->reg_lccr3;
- LCCR2 = fbi->reg_lccr2;
- LCCR1 = fbi->reg_lccr1;
- LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
-
- FDADR0 = fbi->fdadr0;
- FDADR1 = fbi->fdadr1;
- LCCR0 |= LCCR0_ENB;
-
- pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
- pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
- pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
- pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1);
- pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2);
- pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3);
- pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4);
+ lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+ lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
+ lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+
+ lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
+ lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
}
static void pxafb_disable_controller(struct pxafb_info *fbi)
{
- DECLARE_WAITQUEUE(wait, current);
+ uint32_t lccr0;
- pr_debug("pxafb: disabling LCD controller\n");
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (fbi->lccr0 & LCCR0_LCDT) {
+ wait_for_completion_timeout(&fbi->refresh_done,
+ 200 * HZ / 1000);
+ return;
+ }
+#endif
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&fbi->ctrlr_wait, &wait);
+ /* Clear LCD Status Register */
+ lcd_writel(fbi, LCSR, 0xffffffff);
- LCSR = 0xffffffff; /* Clear LCD Status Register */
- LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
- LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
+ lccr0 = lcd_readl(fbi, LCCR0) & ~LCCR0_LDM;
+ lcd_writel(fbi, LCCR0, lccr0);
+ lcd_writel(fbi, LCCR0, lccr0 | LCCR0_DIS);
- schedule_timeout(200 * HZ / 1000);
- remove_wait_queue(&fbi->ctrlr_wait, &wait);
+ wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000);
/* disable LCD controller clock */
clk_disable(fbi->clk);
@@ -883,14 +1032,20 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
{
struct pxafb_info *fbi = dev_id;
- unsigned int lcsr = LCSR;
+ unsigned int lccr0, lcsr = lcd_readl(fbi, LCSR);
if (lcsr & LCSR_LDD) {
- LCCR0 |= LCCR0_LDM;
- wake_up(&fbi->ctrlr_wait);
+ lccr0 = lcd_readl(fbi, LCCR0);
+ lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM);
+ complete(&fbi->disable_done);
}
- LCSR = lcsr;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (lcsr & LCSR_CMD_INT)
+ complete(&fbi->command_done);
+#endif
+
+ lcd_writel(fbi, LCSR, lcsr);
return IRQ_HANDLED;
}
@@ -921,7 +1076,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
*/
if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
fbi->state = state;
- //TODO __pxafb_lcd_power(fbi, 0);
+ /* TODO __pxafb_lcd_power(fbi, 0); */
pxafb_disable_controller(fbi);
}
break;
@@ -948,7 +1103,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
if (old_state == C_DISABLE_CLKCHANGE) {
fbi->state = C_ENABLE;
pxafb_enable_controller(fbi);
- //TODO __pxafb_lcd_power(fbi, 1);
+ /* TODO __pxafb_lcd_power(fbi, 1); */
}
break;
@@ -1019,7 +1174,7 @@ static int
pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
{
struct pxafb_info *fbi = TO_INF(nb, freq_transition);
- //TODO struct cpufreq_freqs *f = data;
+ /* TODO struct cpufreq_freqs *f = data; */
u_int pcd;
switch (val) {
@@ -1030,7 +1185,8 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
case CPUFREQ_POSTCHANGE:
pcd = get_pcd(fbi, fbi->fb.var.pixclock);
set_hsync_time(fbi, pcd);
- fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) |
+ LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break;
}
@@ -1050,18 +1206,8 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
pr_debug("min dma period: %d ps, "
"new clock %d kHz\n", pxafb_display_dma_period(var),
policy->max);
- // TODO: fill in min/max values
- break;
-#if 0
- case CPUFREQ_NOTIFY:
- printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__);
- do {} while(0);
- /* todo: panic if min/max values aren't fulfilled
- * [can't really happen unless there's a bug in the
- * CPU policy verification process *
- */
+ /* TODO: fill in min/max values */
break;
-#endif
}
return 0;
}
@@ -1102,21 +1248,21 @@ static int pxafb_resume(struct platform_device *dev)
*/
static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
{
- u_long palette_mem_size;
-
/*
* We reserve one page for the palette, plus the size
* of the framebuffer.
*/
- fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+ fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
&fbi->map_dma, GFP_KERNEL);
if (fbi->map_cpu) {
/* prevent initial garbage on screen */
memset(fbi->map_cpu, 0, fbi->map_size);
- fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
- fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+ fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
/*
* FIXME: this is actually the wrong thing to place in
* smem_start. But fbdev suffers from the problem that
@@ -1126,27 +1272,86 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
fbi->fb.fix.smem_start = fbi->screen_dma;
fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- palette_mem_size = fbi->palette_size * sizeof(u16);
- else
- palette_mem_size = fbi->palette_size * sizeof(u32);
+ fbi->dma_buff = (void *) fbi->map_cpu;
+ fbi->dma_buff_phys = fbi->map_dma;
+ fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
-
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
+ fbi->n_smart_cmds = 0;
+#endif
}
return fbi->map_cpu ? 0 : -ENOMEM;
}
+static void pxafb_decode_mode_info(struct pxafb_info *fbi,
+ struct pxafb_mode_info *modes,
+ unsigned int num_modes)
+{
+ unsigned int i, smemlen;
+
+ pxafb_setmode(&fbi->fb.var, &modes[0]);
+
+ for (i = 0; i < num_modes; i++) {
+ smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8;
+ if (smemlen > fbi->fb.fix.smem_len)
+ fbi->fb.fix.smem_len = smemlen;
+ }
+}
+
+static void pxafb_decode_mach_info(struct pxafb_info *fbi,
+ struct pxafb_mach_info *inf)
+{
+ unsigned int lcd_conn = inf->lcd_conn;
+
+ fbi->cmap_inverse = inf->cmap_inverse;
+ fbi->cmap_static = inf->cmap_static;
+
+ switch (lcd_conn & 0xf) {
+ case LCD_TYPE_MONO_STN:
+ fbi->lccr0 = LCCR0_CMS;
+ break;
+ case LCD_TYPE_MONO_DSTN:
+ fbi->lccr0 = LCCR0_CMS | LCCR0_SDS;
+ break;
+ case LCD_TYPE_COLOR_STN:
+ fbi->lccr0 = 0;
+ break;
+ case LCD_TYPE_COLOR_DSTN:
+ fbi->lccr0 = LCCR0_SDS;
+ break;
+ case LCD_TYPE_COLOR_TFT:
+ fbi->lccr0 = LCCR0_PAS;
+ break;
+ case LCD_TYPE_SMART_PANEL:
+ fbi->lccr0 = LCCR0_LCDT | LCCR0_PAS;
+ break;
+ default:
+ /* fall back to backward compatibility way */
+ fbi->lccr0 = inf->lccr0;
+ fbi->lccr3 = inf->lccr3;
+ fbi->lccr4 = inf->lccr4;
+ goto decode_mode;
+ }
+
+ if (lcd_conn == LCD_MONO_STN_8BPP)
+ fbi->lccr0 |= LCCR0_DPD;
+
+ fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff);
+ fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0;
+ fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0;
+
+decode_mode:
+ pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
+}
+
static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
{
struct pxafb_info *fbi;
void *addr;
struct pxafb_mach_info *inf = dev->platform_data;
struct pxafb_mode_info *mode = inf->modes;
- int i, smemlen;
/* Alloc the pxafb_info and pseudo_palette in one step */
fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1186,187 +1391,233 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
addr = addr + sizeof(struct pxafb_info);
fbi->fb.pseudo_palette = addr;
- pxafb_setmode(&fbi->fb.var, mode);
-
- fbi->cmap_inverse = inf->cmap_inverse;
- fbi->cmap_static = inf->cmap_static;
+ fbi->state = C_STARTUP;
+ fbi->task_state = (u_char)-1;
- fbi->lccr0 = inf->lccr0;
- fbi->lccr3 = inf->lccr3;
- fbi->lccr4 = inf->lccr4;
- fbi->state = C_STARTUP;
- fbi->task_state = (u_char)-1;
-
- for (i = 0; i < inf->num_modes; i++) {
- smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
- if (smemlen > fbi->fb.fix.smem_len)
- fbi->fb.fix.smem_len = smemlen;
- }
+ pxafb_decode_mach_info(fbi, inf);
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, pxafb_task);
init_MUTEX(&fbi->ctrlr_sem);
+ init_completion(&fbi->disable_done);
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ init_completion(&fbi->command_done);
+ init_completion(&fbi->refresh_done);
+#endif
return fbi;
}
#ifdef CONFIG_FB_PXA_PARAMETERS
-static int __init pxafb_parse_options(struct device *dev, char *options)
+static int __init parse_opt_mode(struct device *dev, const char *this_opt)
+{
+ struct pxafb_mach_info *inf = dev->platform_data;
+
+ const char *name = this_opt+5;
+ unsigned int namelen = strlen(name);
+ int res_specified = 0, bpp_specified = 0;
+ unsigned int xres = 0, yres = 0, bpp = 0;
+ int yres_specified = 0;
+ int i;
+ for (i = namelen-1; i >= 0; i--) {
+ switch (name[i]) {
+ case '-':
+ namelen = i;
+ if (!bpp_specified && !yres_specified) {
+ bpp = simple_strtoul(&name[i+1], NULL, 0);
+ bpp_specified = 1;
+ } else
+ goto done;
+ break;
+ case 'x':
+ if (!yres_specified) {
+ yres = simple_strtoul(&name[i+1], NULL, 0);
+ yres_specified = 1;
+ } else
+ goto done;
+ break;
+ case '0' ... '9':
+ break;
+ default:
+ goto done;
+ }
+ }
+ if (i < 0 && yres_specified) {
+ xres = simple_strtoul(name, NULL, 0);
+ res_specified = 1;
+ }
+done:
+ if (res_specified) {
+ dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
+ inf->modes[0].xres = xres; inf->modes[0].yres = yres;
+ }
+ if (bpp_specified)
+ switch (bpp) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ inf->modes[0].bpp = bpp;
+ dev_info(dev, "overriding bit depth: %d\n", bpp);
+ break;
+ default:
+ dev_err(dev, "Depth %d is not valid\n", bpp);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __init parse_opt(struct device *dev, char *this_opt)
{
struct pxafb_mach_info *inf = dev->platform_data;
+ struct pxafb_mode_info *mode = &inf->modes[0];
+ char s[64];
+
+ s[0] = '\0';
+
+ if (!strncmp(this_opt, "mode:", 5)) {
+ return parse_opt_mode(dev, this_opt);
+ } else if (!strncmp(this_opt, "pixclock:", 9)) {
+ mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "pixclock: %ld\n", mode->pixclock);
+ } else if (!strncmp(this_opt, "left:", 5)) {
+ mode->left_margin = simple_strtoul(this_opt+5, NULL, 0);
+ sprintf(s, "left: %u\n", mode->left_margin);
+ } else if (!strncmp(this_opt, "right:", 6)) {
+ mode->right_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "right: %u\n", mode->right_margin);
+ } else if (!strncmp(this_opt, "upper:", 6)) {
+ mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "upper: %u\n", mode->upper_margin);
+ } else if (!strncmp(this_opt, "lower:", 6)) {
+ mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "lower: %u\n", mode->lower_margin);
+ } else if (!strncmp(this_opt, "hsynclen:", 9)) {
+ mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "hsynclen: %u\n", mode->hsync_len);
+ } else if (!strncmp(this_opt, "vsynclen:", 9)) {
+ mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "vsynclen: %u\n", mode->vsync_len);
+ } else if (!strncmp(this_opt, "hsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ sprintf(s, "hsync: Active Low\n");
+ mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ } else {
+ sprintf(s, "hsync: Active High\n");
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ }
+ } else if (!strncmp(this_opt, "vsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ sprintf(s, "vsync: Active Low\n");
+ mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ } else {
+ sprintf(s, "vsync: Active High\n");
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+ } else if (!strncmp(this_opt, "dpc:", 4)) {
+ if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
+ sprintf(s, "double pixel clock: false\n");
+ inf->lccr3 &= ~LCCR3_DPC;
+ } else {
+ sprintf(s, "double pixel clock: true\n");
+ inf->lccr3 |= LCCR3_DPC;
+ }
+ } else if (!strncmp(this_opt, "outputen:", 9)) {
+ if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
+ sprintf(s, "output enable: active low\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
+ } else {
+ sprintf(s, "output enable: active high\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
+ }
+ } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+ if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
+ sprintf(s, "pixel clock polarity: falling edge\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
+ } else {
+ sprintf(s, "pixel clock polarity: rising edge\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
+ }
+ } else if (!strncmp(this_opt, "color", 5)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
+ } else if (!strncmp(this_opt, "mono", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
+ } else if (!strncmp(this_opt, "active", 6)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
+ } else if (!strncmp(this_opt, "passive", 7)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
+ } else if (!strncmp(this_opt, "single", 6)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
+ } else if (!strncmp(this_opt, "dual", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
+ } else if (!strncmp(this_opt, "4pix", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
+ } else if (!strncmp(this_opt, "8pix", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
+ } else {
+ dev_err(dev, "unknown option: %s\n", this_opt);
+ return -EINVAL;
+ }
+
+ if (s[0] != '\0')
+ dev_info(dev, "override %s", s);
+
+ return 0;
+}
+
+static int __init pxafb_parse_options(struct device *dev, char *options)
+{
char *this_opt;
+ int ret;
- if (!options || !*options)
- return 0;
+ if (!options || !*options)
+ return 0;
dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
/* could be made table driven or similar?... */
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!strncmp(this_opt, "mode:", 5)) {
- const char *name = this_opt+5;
- unsigned int namelen = strlen(name);
- int res_specified = 0, bpp_specified = 0;
- unsigned int xres = 0, yres = 0, bpp = 0;
- int yres_specified = 0;
- int i;
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '-':
- namelen = i;
- if (!bpp_specified && !yres_specified) {
- bpp = simple_strtoul(&name[i+1], NULL, 0);
- bpp_specified = 1;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified) {
- yres = simple_strtoul(&name[i+1], NULL, 0);
- yres_specified = 1;
- } else
- goto done;
- break;
- case '0' ... '9':
- break;
- default:
- goto done;
- }
- }
- if (i < 0 && yres_specified) {
- xres = simple_strtoul(name, NULL, 0);
- res_specified = 1;
- }
- done:
- if (res_specified) {
- dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
- inf->modes[0].xres = xres; inf->modes[0].yres = yres;
- }
- if (bpp_specified)
- switch (bpp) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- inf->modes[0].bpp = bpp;
- dev_info(dev, "overriding bit depth: %d\n", bpp);
- break;
- default:
- dev_err(dev, "Depth %d is not valid\n", bpp);
- }
- } else if (!strncmp(this_opt, "pixclock:", 9)) {
- inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock);
- } else if (!strncmp(this_opt, "left:", 5)) {
- inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0);
- dev_info(dev, "override left: %u\n", inf->modes[0].left_margin);
- } else if (!strncmp(this_opt, "right:", 6)) {
- inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override right: %u\n", inf->modes[0].right_margin);
- } else if (!strncmp(this_opt, "upper:", 6)) {
- inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin);
- } else if (!strncmp(this_opt, "lower:", 6)) {
- inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin);
- } else if (!strncmp(this_opt, "hsynclen:", 9)) {
- inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len);
- } else if (!strncmp(this_opt, "vsynclen:", 9)) {
- inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len);
- } else if (!strncmp(this_opt, "hsync:", 6)) {
- if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
- dev_info(dev, "override hsync: Active Low\n");
- inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT;
- } else {
- dev_info(dev, "override hsync: Active High\n");
- inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT;
- }
- } else if (!strncmp(this_opt, "vsync:", 6)) {
- if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
- dev_info(dev, "override vsync: Active Low\n");
- inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT;
- } else {
- dev_info(dev, "override vsync: Active High\n");
- inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT;
- }
- } else if (!strncmp(this_opt, "dpc:", 4)) {
- if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
- dev_info(dev, "override double pixel clock: false\n");
- inf->lccr3 &= ~LCCR3_DPC;
- } else {
- dev_info(dev, "override double pixel clock: true\n");
- inf->lccr3 |= LCCR3_DPC;
- }
- } else if (!strncmp(this_opt, "outputen:", 9)) {
- if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
- dev_info(dev, "override output enable: active low\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
- } else {
- dev_info(dev, "override output enable: active high\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
- }
- } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
- if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
- dev_info(dev, "override pixel clock polarity: falling edge\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
- } else {
- dev_info(dev, "override pixel clock polarity: rising edge\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
- }
- } else if (!strncmp(this_opt, "color", 5)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
- } else if (!strncmp(this_opt, "mono", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
- } else if (!strncmp(this_opt, "active", 6)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
- } else if (!strncmp(this_opt, "passive", 7)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
- } else if (!strncmp(this_opt, "single", 6)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
- } else if (!strncmp(this_opt, "dual", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
- } else if (!strncmp(this_opt, "4pix", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
- } else if (!strncmp(this_opt, "8pix", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
- } else {
- dev_err(dev, "unknown option: %s\n", this_opt);
- return -EINVAL;
- }
- }
- return 0;
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ ret = parse_opt(dev, this_opt);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static char g_options[256] __devinitdata = "";
+#ifndef CONFIG_MODULES
+static int __devinit pxafb_setup_options(void)
+{
+ char *options = NULL;
+
+ if (fb_get_options("pxafb", &options))
+ return -ENODEV;
+
+ if (options)
+ strlcpy(g_options, options, sizeof(g_options));
+
+ return 0;
}
+#else
+#define pxafb_setup_options() (0)
+
+module_param_string(options, g_options, sizeof(g_options), 0);
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
+#endif
+
+#else
+#define pxafb_parse_options(...) (0)
+#define pxafb_setup_options() (0)
#endif
static int __init pxafb_probe(struct platform_device *dev)
{
struct pxafb_info *fbi;
struct pxafb_mach_info *inf;
- int ret;
+ struct resource *r;
+ int irq, ret;
dev_dbg(&dev->dev, "pxafb_probe\n");
@@ -1376,38 +1627,45 @@ static int __init pxafb_probe(struct platform_device *dev)
if (!inf)
goto failed;
-#ifdef CONFIG_FB_PXA_PARAMETERS
ret = pxafb_parse_options(&dev->dev, g_options);
if (ret < 0)
goto failed;
-#endif
#ifdef DEBUG_VAR
- /* Check for various illegal bit-combinations. Currently only
+ /* Check for various illegal bit-combinations. Currently only
* a warning is given. */
- if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
- inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
- if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
- inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
- if (inf->lccr0 & LCCR0_DPD &&
+ if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+ dev_warn(&dev->dev, "machine LCCR0 setting contains "
+ "illegal bits: %08x\n",
+ inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+ if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+ dev_warn(&dev->dev, "machine LCCR3 setting contains "
+ "illegal bits: %08x\n",
+ inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+ if (inf->lccr0 & LCCR0_DPD &&
((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
(inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
(inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
- dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
- " single panel mode\n");
- if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+ dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is "
+ "only valid in passive mono"
+ " single panel mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
(inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
- dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
- if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
- (inf->modes->upper_margin || inf->modes->lower_margin))
- dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
+ dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+ (inf->modes->upper_margin || inf->modes->lower_margin))
+ dev_warn(&dev->dev, "Upper and lower margins must be 0 in "
+ "passive mode\n");
#endif
- dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
- if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
+ dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",
+ inf->modes->xres,
+ inf->modes->yres,
+ inf->modes->bpp);
+ if (inf->modes->xres == 0 ||
+ inf->modes->yres == 0 ||
+ inf->modes->bpp == 0) {
dev_err(&dev->dev, "Invalid resolution or bit depth\n");
ret = -EINVAL;
goto failed;
@@ -1416,26 +1674,62 @@ static int __init pxafb_probe(struct platform_device *dev)
pxafb_lcd_power = inf->pxafb_lcd_power;
fbi = pxafb_init_fbinfo(&dev->dev);
if (!fbi) {
+ /* only reason for pxafb_init_fbinfo to fail is kmalloc */
dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
- ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+ ret = -ENOMEM;
goto failed;
}
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&dev->dev, "no I/O memory resource defined\n");
+ ret = -ENODEV;
+ goto failed;
+ }
+
+ r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
+ if (r == NULL) {
+ dev_err(&dev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto failed;
+ }
+
+ fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
+ if (fbi->mmio_base == NULL) {
+ dev_err(&dev->dev, "failed to map I/O memory\n");
+ ret = -EBUSY;
+ goto failed_free_res;
+ }
+
/* Initialize video memory */
ret = pxafb_map_video_memory(fbi);
if (ret) {
dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
- goto failed;
+ goto failed_free_io;
+ }
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no IRQ defined\n");
+ ret = -ENODEV;
+ goto failed_free_mem;
}
- ret = request_irq(IRQ_LCD, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
if (ret) {
dev_err(&dev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
- goto failed;
+ goto failed_free_mem;
}
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ ret = pxafb_smart_init(fbi);
+ if (ret) {
+ dev_err(&dev->dev, "failed to initialize smartpanel\n");
+ goto failed_free_irq;
+ }
+#endif
/*
* This makes sure that our colour bitfield
* descriptors are correctly initialised.
@@ -1447,19 +1741,18 @@ static int __init pxafb_probe(struct platform_device *dev)
ret = register_framebuffer(&fbi->fb);
if (ret < 0) {
- dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret);
- goto failed;
+ dev_err(&dev->dev,
+ "Failed to register framebuffer device: %d\n", ret);
+ goto failed_free_irq;
}
-#ifdef CONFIG_PM
- // TODO
-#endif
-
#ifdef CONFIG_CPU_FREQ
fbi->freq_transition.notifier_call = pxafb_freq_transition;
fbi->freq_policy.notifier_call = pxafb_freq_policy;
- cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
- cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
+ cpufreq_register_notifier(&fbi->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ cpufreq_register_notifier(&fbi->freq_policy,
+ CPUFREQ_POLICY_NOTIFIER);
#endif
/*
@@ -1469,6 +1762,15 @@ static int __init pxafb_probe(struct platform_device *dev)
return 0;
+failed_free_irq:
+ free_irq(irq, fbi);
+failed_free_res:
+ release_mem_region(r->start, r->end - r->start + 1);
+failed_free_io:
+ iounmap(fbi->mmio_base);
+failed_free_mem:
+ dma_free_writecombine(&dev->dev, fbi->map_size,
+ fbi->map_cpu, fbi->map_dma);
failed:
platform_set_drvdata(dev, NULL);
kfree(fbi);
@@ -1477,40 +1779,18 @@ failed:
static struct platform_driver pxafb_driver = {
.probe = pxafb_probe,
-#ifdef CONFIG_PM
.suspend = pxafb_suspend,
.resume = pxafb_resume,
-#endif
.driver = {
.name = "pxa2xx-fb",
},
};
-#ifndef MODULE
-static int __devinit pxafb_setup(char *options)
-{
-# ifdef CONFIG_FB_PXA_PARAMETERS
- if (options)
- strlcpy(g_options, options, sizeof(g_options));
-# endif
- return 0;
-}
-#else
-# ifdef CONFIG_FB_PXA_PARAMETERS
-module_param_string(options, g_options, sizeof(g_options), 0);
-MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
-# endif
-#endif
-
static int __devinit pxafb_init(void)
{
-#ifndef MODULE
- char *option = NULL;
+ if (pxafb_setup_options())
+ return -EINVAL;
- if (fb_get_options("pxafb", &option))
- return -ENODEV;
- pxafb_setup(option);
-#endif
return platform_driver_register(&pxafb_driver);
}
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index d920b8a14c35..8238dc826429 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -21,14 +21,6 @@
* for more details.
*/
-/* Shadows for LCD controller registers */
-struct pxafb_lcd_reg {
- unsigned int lccr0;
- unsigned int lccr1;
- unsigned int lccr2;
- unsigned int lccr3;
-};
-
/* PXA LCD DMA descriptor */
struct pxafb_dma_descriptor {
unsigned int fdadr;
@@ -37,11 +29,49 @@ struct pxafb_dma_descriptor {
unsigned int ldcmd;
};
+enum {
+ PAL_NONE = -1,
+ PAL_BASE = 0,
+ PAL_OV1 = 1,
+ PAL_OV2 = 2,
+ PAL_MAX,
+};
+
+enum {
+ DMA_BASE = 0,
+ DMA_UPPER = 0,
+ DMA_LOWER = 1,
+ DMA_OV1 = 1,
+ DMA_OV2_Y = 2,
+ DMA_OV2_Cb = 3,
+ DMA_OV2_Cr = 4,
+ DMA_CURSOR = 5,
+ DMA_CMD = 6,
+ DMA_MAX,
+};
+
+/* maximum palette size - 256 entries, each 4 bytes long */
+#define PALETTE_SIZE (256 * 4)
+#define CMD_BUFF_SIZE (1024 * 50)
+
+struct pxafb_dma_buff {
+ unsigned char palette[PAL_MAX * PALETTE_SIZE];
+ uint16_t cmd_buff[CMD_BUFF_SIZE];
+ struct pxafb_dma_descriptor pal_desc[PAL_MAX];
+ struct pxafb_dma_descriptor dma_desc[DMA_MAX];
+};
+
struct pxafb_info {
struct fb_info fb;
struct device *dev;
struct clk *clk;
+ void __iomem *mmio_base;
+
+ struct pxafb_dma_buff *dma_buff;
+ dma_addr_t dma_buff_phys;
+ dma_addr_t fdadr[DMA_MAX];
+
/*
* These are the addresses we mapped
* the framebuffer memory region to.
@@ -55,19 +85,8 @@ struct pxafb_info {
u_char * screen_cpu; /* virtual address of frame buffer */
dma_addr_t screen_dma; /* physical address of frame buffer */
u16 * palette_cpu; /* virtual address of palette memory */
- dma_addr_t palette_dma; /* physical address of palette memory */
u_int palette_size;
-
- /* DMA descriptors */
- struct pxafb_dma_descriptor * dmadesc_fblow_cpu;
- dma_addr_t dmadesc_fblow_dma;
- struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu;
- dma_addr_t dmadesc_fbhigh_dma;
- struct pxafb_dma_descriptor * dmadesc_palette_cpu;
- dma_addr_t dmadesc_palette_dma;
-
- dma_addr_t fdadr0;
- dma_addr_t fdadr1;
+ ssize_t video_offset;
u_int lccr0;
u_int lccr3;
@@ -81,6 +100,7 @@ struct pxafb_info {
u_int reg_lccr2;
u_int reg_lccr3;
u_int reg_lccr4;
+ u_int reg_cmdcr;
unsigned long hsync_time;
@@ -90,6 +110,16 @@ struct pxafb_info {
wait_queue_head_t ctrlr_wait;
struct work_struct task;
+ struct completion disable_done;
+
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ uint16_t *smart_cmds;
+ size_t n_smart_cmds;
+ struct completion command_done;
+ struct completion refresh_done;
+ struct task_struct *smart_thread;
+#endif
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
struct notifier_block freq_policy;
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
index 4deaac05b938..37d764ad56b0 100644
--- a/drivers/video/sbuslib.c
+++ b/drivers/video/sbuslib.c
@@ -10,18 +10,19 @@
#include <linux/fb.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
+#include <linux/of_device.h>
-#include <asm/oplib.h>
#include <asm/fbio.h>
#include "sbuslib.h"
-void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp)
+void sbusfb_fill_var(struct fb_var_screeninfo *var, struct device_node *dp,
+ int bpp)
{
memset(var, 0, sizeof(*var));
- var->xres = prom_getintdefault(prom_node, "width", 1152);
- var->yres = prom_getintdefault(prom_node, "height", 900);
+ var->xres = of_getintprop_default(dp, "width", 1152);
+ var->yres = of_getintprop_default(dp, "height", 900);
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
var->bits_per_pixel = bpp;
diff --git a/drivers/video/sbuslib.h b/drivers/video/sbuslib.h
index 492828c3fe8f..7ba3250236bd 100644
--- a/drivers/video/sbuslib.h
+++ b/drivers/video/sbuslib.h
@@ -11,7 +11,8 @@ struct sbus_mmap_map {
#define SBUS_MMAP_FBSIZE(n) (-n)
#define SBUS_MMAP_EMPTY 0x80000000
-extern void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp);
+extern void sbusfb_fill_var(struct fb_var_screeninfo *var,
+ struct device_node *dp, int bpp);
struct vm_area_struct;
extern int sbusfb_mmap_helper(struct sbus_mmap_map *map,
unsigned long physbase, unsigned long fbsize,
@@ -21,6 +22,6 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
struct fb_info *info,
int type, int fb_depth, unsigned long fb_size);
int sbusfb_compat_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg);
+ unsigned long arg);
#endif /* _SBUSLIB_H */
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c
index c3869a96ab58..b1dde09e7015 100644
--- a/drivers/video/sunxvr2500.c
+++ b/drivers/video/sunxvr2500.c
@@ -9,10 +9,9 @@
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
struct s3d_info {
struct fb_info *info;
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
index 71bf3f1f00bc..c2ba51b7ea18 100644
--- a/drivers/video/sunxvr500.c
+++ b/drivers/video/sunxvr500.c
@@ -9,10 +9,9 @@
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
/* XXX This device has a 'dev-comm' property which aparently is
* XXX a pointer into the openfirmware's address space which is
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index a71774305772..2a03f78bbb0d 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -17,10 +17,9 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -84,7 +83,7 @@ struct tcx_tec {
struct tcx_thc {
u32 thc_rev;
- u32 thc_pad0[511];
+ u32 thc_pad0[511];
u32 thc_hs; /* hsync timing */
u32 thc_hsdvs;
u32 thc_hd;
@@ -126,10 +125,10 @@ struct tcx_par {
};
/* Reset control plane so that WID is 8-bit plane. */
-static void __tcx_set_control_plane (struct tcx_par *par)
+static void __tcx_set_control_plane(struct tcx_par *par)
{
u32 __iomem *p, *pend;
-
+
if (par->lowdepth)
return;
@@ -143,8 +142,8 @@ static void __tcx_set_control_plane (struct tcx_par *par)
sbus_writel(tmp, p);
}
}
-
-static void tcx_reset (struct fb_info *info)
+
+static void tcx_reset(struct fb_info *info)
{
struct tcx_par *par = (struct tcx_par *) info->par;
unsigned long flags;
@@ -365,7 +364,8 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
info->screen_base, par->fbsize);
}
-static int __devinit tcx_init_one(struct of_device *op)
+static int __devinit tcx_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct fb_info *info;
@@ -384,7 +384,7 @@ static int __devinit tcx_init_one(struct of_device *op)
par->lowdepth =
(of_find_property(dp, "tcx-8-bit", NULL) != NULL);
- sbusfb_fill_var(&info->var, dp->node, 8);
+ sbusfb_fill_var(&info->var, dp, 8);
info->var.red.length = 8;
info->var.green.length = 8;
info->var.blue.length = 8;
@@ -488,13 +488,6 @@ out_err:
return err;
}
-static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
-
- return tcx_init_one(op);
-}
-
static int __devexit tcx_remove(struct of_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index bd54cd0de39a..beefab2992c0 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -27,7 +27,6 @@
#define VERSION "0.7.8-NEWAPI"
struct tridentfb_par {
- int vclk; /* in MHz */
void __iomem *io_virt; /* iospace virtual memory address */
};
@@ -669,27 +668,26 @@ static void set_screen_start(int base)
(read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
}
-/* Use 20.12 fixed-point for NTSC value and frequency calculation */
-#define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
-
/* Set dotclock frequency */
-static void set_vclk(int freq)
+static void set_vclk(unsigned long freq)
{
int m, n, k;
- int f, fi, d, di;
+ unsigned long f, fi, d, di;
unsigned char lo = 0, hi = 0;
- d = 20;
+ d = 20000;
for (k = 2; k >= 0; k--)
for (m = 0; m < 63; m++)
for (n = 0; n < 128; n++) {
- fi = calc_freq(n, m, k);
+ fi = ((14318l * (n + 8)) / (m + 2)) >> k;
if ((di = abs(fi - freq)) < d) {
d = di;
f = fi;
lo = n;
hi = (k << 6) | m;
}
+ if (fi > freq)
+ break;
}
if (chip3D) {
write3C4(ClockHigh, hi);
@@ -888,6 +886,8 @@ static int tridentfb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
int bpp = var->bits_per_pixel;
unsigned char tmp;
+ unsigned long vclk;
+
debug("enter\n");
hdispend = var->xres / 8 - 1;
hsyncstart = (var->xres + var->right_margin) / 8;
@@ -905,7 +905,6 @@ static int tridentfb_set_par(struct fb_info *info)
vblankstart = var->yres;
vblankend = vtotal + 2;
- enable_mmio();
crtc_unlock();
write3CE(CyberControl, 8);
@@ -1015,11 +1014,11 @@ static int tridentfb_set_par(struct fb_info *info)
write3X4(Performance, 0x92);
write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
- /* convert from picoseconds to MHz */
- par->vclk = 1000000 / info->var.pixclock;
+ /* convert from picoseconds to kHz */
+ vclk = PICOS2KHZ(info->var.pixclock);
if (bpp == 32)
- par->vclk *= 2;
- set_vclk(par->vclk);
+ vclk *= 2;
+ set_vclk(vclk);
write3C4(0, 3);
write3C4(1, 1); /* set char clock 8 dots wide */
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b535483bc556..13866789b356 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -80,19 +80,51 @@ static void add_status(struct virtio_device *dev, unsigned status)
dev->config->set_status(dev, dev->config->get_status(dev) | status);
}
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ unsigned int i;
+ struct virtio_driver *drv = container_of(vdev->dev.driver,
+ struct virtio_driver, driver);
+
+ for (i = 0; i < drv->feature_table_size; i++)
+ if (drv->feature_table[i] == fbit)
+ return;
+ BUG();
+}
+EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
+
static int virtio_dev_probe(struct device *_d)
{
- int err;
+ int err, i;
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_driver *drv = container_of(dev->dev.driver,
struct virtio_driver, driver);
+ u32 device_features;
+ /* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+
+ /* Figure out what features the device supports. */
+ device_features = dev->config->get_features(dev);
+
+ /* Features supported by both device and driver into dev->features. */
+ memset(dev->features, 0, sizeof(dev->features));
+ for (i = 0; i < drv->feature_table_size; i++) {
+ unsigned int f = drv->feature_table[i];
+ BUG_ON(f >= 32);
+ if (device_features & (1 << f))
+ set_bit(f, dev->features);
+ }
+
err = drv->probe(dev);
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
- else
+ else {
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+ /* They should never have set feature bits beyond 32 */
+ dev->config->set_features(dev, dev->features[0]);
+ }
return err;
}
@@ -114,6 +146,8 @@ static int virtio_dev_remove(struct device *_d)
int register_virtio_driver(struct virtio_driver *driver)
{
+ /* Catch this early. */
+ BUG_ON(driver->feature_table_size && !driver->feature_table);
driver->driver.bus = &virtio_bus;
driver->driver.probe = virtio_dev_probe;
driver->driver.remove = virtio_dev_remove;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 0b3efc31ee6d..bfef604160d1 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -155,9 +155,9 @@ static void virtballoon_changed(struct virtio_device *vdev)
static inline s64 towards_target(struct virtio_balloon *vb)
{
u32 v;
- __virtio_config_val(vb->vdev,
- offsetof(struct virtio_balloon_config, num_pages),
- &v);
+ vb->vdev->config->get(vb->vdev,
+ offsetof(struct virtio_balloon_config, num_pages),
+ &v, sizeof(v));
return v - vb->num_pages;
}
@@ -227,7 +227,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
}
vb->tell_host_first
- = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+ = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
return 0;
@@ -259,7 +259,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
kfree(vb);
}
+static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+
static struct virtio_driver virtio_balloon = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index c0df924766a7..27e9fc9117cd 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -87,23 +87,22 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
return container_of(vdev, struct virtio_pci_device, vdev);
}
-/* virtio config->feature() implementation */
-static bool vp_feature(struct virtio_device *vdev, unsigned bit)
+/* virtio config->get_features() implementation */
+static u32 vp_get_features(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ /* When someone needs more than 32 feature bits, we'll need to
+ * steal a bit to indicate that the rest are somewhere else. */
+ return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+/* virtio config->set_features() implementation */
+static void vp_set_features(struct virtio_device *vdev, u32 features)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- u32 mask;
-
- /* Since this function is supposed to have the side effect of
- * enabling a queried feature, we simulate that by doing a read
- * from the host feature bitmask and then writing to the guest
- * feature bitmask */
- mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
- if (mask & (1 << bit)) {
- mask |= (1 << bit);
- iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
- }
- return !!(mask & (1 << bit));
+ iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
}
/* virtio config->get() implementation */
@@ -145,14 +144,14 @@ static void vp_set_status(struct virtio_device *vdev, u8 status)
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
/* We should never be setting status to 0. */
BUG_ON(status == 0);
- return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
}
static void vp_reset(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
/* 0 status means a reset. */
- return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
}
/* the notify function used when creating a virt queue */
@@ -293,7 +292,6 @@ static void vp_del_vq(struct virtqueue *vq)
}
static struct virtio_config_ops virtio_pci_config_ops = {
- .feature = vp_feature,
.get = vp_get,
.set = vp_set,
.get_status = vp_get_status,
@@ -301,6 +299,8 @@ static struct virtio_config_ops virtio_pci_config_ops = {
.reset = vp_reset,
.find_vq = vp_find_vq,
.del_vq = vp_del_vq,
+ .get_features = vp_get_features,
+ .set_features = vp_set_features,
};
/* the PCI probing function */
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index c2fa5c630813..937a49d6772c 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -184,6 +184,11 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
START_USE(vq);
+ if (unlikely(vq->broken)) {
+ END_USE(vq);
+ return NULL;
+ }
+
if (!more_used(vq)) {
pr_debug("No more buffers in queue\n");
END_USE(vq);
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h
index fe6bdf43380f..e6ab7cf08f88 100644
--- a/drivers/w1/w1_log.h
+++ b/drivers/w1/w1_log.h
@@ -30,7 +30,7 @@
# define assert(expr) \
if(unlikely(!(expr))) { \
printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
+ #expr, __FILE__, __func__, __LINE__); \
}
#endif
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 2ce4cebc31d9..099b6fb5b5cb 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/zorro.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -76,36 +77,58 @@ proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t *
}
static const struct file_operations proc_bus_zorro_operations = {
+ .owner = THIS_MODULE,
.llseek = proc_bus_zorro_lseek,
.read = proc_bus_zorro_read,
};
-static int
-get_zorro_dev_info(char *buf, char **start, off_t pos, int count)
+static void * zorro_seq_start(struct seq_file *m, loff_t *pos)
{
- u_int slot;
- off_t at = 0;
- int len, cnt;
-
- for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) {
- struct zorro_dev *z = &zorro_autocon[slot];
- len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot,
- z->id, (unsigned long)zorro_resource_start(z),
- (unsigned long)zorro_resource_len(z),
- z->rom.er_Type);
- at += len;
- if (at >= pos) {
- if (!*start) {
- *start = buf + (pos - (at - len));
- cnt = at - pos;
- } else
- cnt += len;
- buf += len;
- }
- }
- return (count > cnt) ? cnt : count;
+ return (*pos < zorro_num_autocon) ? pos : NULL;
+}
+
+static void * zorro_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return (*pos < zorro_num_autocon) ? pos : NULL;
+}
+
+static void zorro_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int zorro_seq_show(struct seq_file *m, void *v)
+{
+ u_int slot = *(loff_t *)v;
+ struct zorro_dev *z = &zorro_autocon[slot];
+
+ seq_printf(m, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, z->id,
+ (unsigned long)zorro_resource_start(z),
+ (unsigned long)zorro_resource_len(z),
+ z->rom.er_Type);
+ return 0;
+}
+
+static const struct seq_operations zorro_devices_seq_ops = {
+ .start = zorro_seq_start,
+ .next = zorro_seq_next,
+ .stop = zorro_seq_stop,
+ .show = zorro_seq_show,
+};
+
+static int zorro_devices_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &zorro_devices_seq_ops);
}
+static const struct file_operations zorro_devices_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = zorro_devices_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static struct proc_dir_entry *proc_bus_zorro_dir;
static int __init zorro_proc_attach_device(u_int slot)
@@ -114,11 +137,11 @@ static int __init zorro_proc_attach_device(u_int slot)
char name[4];
sprintf(name, "%02x", slot);
- entry = create_proc_entry(name, 0, proc_bus_zorro_dir);
+ entry = proc_create_data(name, 0, proc_bus_zorro_dir,
+ &proc_bus_zorro_operations,
+ &zorro_autocon[slot]);
if (!entry)
return -ENOMEM;
- entry->proc_fops = &proc_bus_zorro_operations;
- entry->data = &zorro_autocon[slot];
entry->size = sizeof(struct zorro_dev);
return 0;
}
@@ -128,9 +151,9 @@ static int __init zorro_proc_init(void)
u_int slot;
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
- proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus);
- create_proc_info_entry("devices", 0, proc_bus_zorro_dir,
- get_zorro_dev_info);
+ proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL);
+ proc_create("devices", 0, proc_bus_zorro_dir,
+ &zorro_devices_proc_fops);
for (slot = 0; slot < zorro_num_autocon; slot++)
zorro_proc_attach_device(slot);
}